【问题标题】:Generating name based on ID and current year using SQL Server使用 SQL Server 根据 ID 和当前年份生成名称
【发布时间】:2019-12-06 14:17:09
【问题描述】:

我正在尝试根据ID(主键列)的值为ProjektNummer(名称)列生成值。

例如,当ID142,那么ProjektNummer 应该是1914219 表示当前年份,142 是其ID 的值。

现在,当年份发生变化时,项目名称列值中的id部分需要从零重新开始,而实际ID应该跟随标识并像往常一样加1。

所以如果 2019 年的最后一条记录 ID=164,那么 2020 年的第一条记录应该是:

ID: 165 ProjektNummer: 20001

.. 2020 年的第二个记录是:

ID: 166 ProjektNummer: 20002

实现此目的的一种方法是创建一个新视图,例如“vMaxLastId”并存储相应年份的“ID”最大值。该记录将在另一个触发器中用作参考。

因此,如果 2020 年的第一条记录的 ID:165 另一个触发器将在插入新记录后从“ID”的值中减去 2019 年的值 (164)(存储在视图中)在“table1”中使用第二个触发器。 (这应该在插入之前完成)

165-164=1
166-164=2
167-164=3
....

当年份从 2019 年更改为 2020 年时,2020 年的最大 ID 和年份将作为新记录添加到视图中。我已经实现了这一点,但这种方法存在多个问题。

请建议我任何可能的方法来解决这个问题。我愿意对数据库、查询或触发器或整个概念进行任何形式的更改。

【问题讨论】:

  • 您可能有一个单独的表,其中包含每年的最大 id,并通过触发器保持最新状态。如果您有大量插入,这可能不是一个有效的解决方案。

标签: sql sql-server database triggers database-trigger


【解决方案1】:

我首先想到的是创建一个SEQUENCE 对象来生成值的ID 部分。由于编号没有花哨的规则,所以应该这样做。

CREATE SEQUENCE dbo.ProjektID;

这会给你一个bigint。要使用它,CONCAT 到当前年份,并将填充零放在序列值上。您可以将其设置为列的默认值。

CONCAT( YEAR( GETDATE() ) % 100 , RIGHT( CONCAT('000', NEXT VALUE FOR dbo.ProjektID), 3))

然后安排一个作业在一年中的第一天午夜运行以重新启动序列。

ALTER SEQUENCE dbo.ProjektID
  RESTART;

我认为这可以满足您的要求。

【讨论】:

  • 感谢您的回答。我已经实施了。有没有办法测试这个工作?
【解决方案2】:

我能想到的最实用的解决方案是在该特定主表上使用INSTEAD OF 触发器。

我的测试表:

CREATE TABLE dbo.MyTestProject
(
  id            INT          IDENTITY(1, 1) NOT NULL PRIMARY KEY
, dateInserted  DATETIME2(7) NOT NULL
, projectNumber INT          NULL
);

以及示例触发器:

CREATE TRIGGER dbo.triMyTestProject
ON dbo.MyTestProject
INSTEAD OF INSERT
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE
    @maxYear      INT
  , @maxNumber    INT
  , @startNumber  INT
  , @dateInserted DATETIME2;

  SELECT
       @dateInserted = dateInserted
  FROM Inserted;

  SET @startNumber = CAST(FORMAT(@dateInserted, 'yy') AS INT) * 1000 + 1;

  SELECT
       @maxNumber = MAX(projectNumber)
     , @maxYear   = ISNULL(MAX(YEAR(dateInserted)), YEAR(@dateInserted))
  FROM dbo.MyTestProject;

  INSERT INTO dbo.MyTestProject
    (
      dateInserted
    , projectNumber
    )
  VALUES
    (
      @dateInserted, IIF(YEAR(@dateInserted) > @maxYear OR @maxNumber IS NULL, @startNumber, @maxNumber + 1)
    );
END;

添加测试数据:

INSERT INTO dbo.MyTestProject (dateInserted) VALUES (SYSDATETIME());
INSERT INTO dbo.MyTestProject (dateInserted) VALUES (SYSDATETIME());
INSERT INTO dbo.MyTestProject (dateInserted) VALUES (SYSDATETIME());
INSERT INTO dbo.MyTestProject (dateInserted) VALUES ('20200102');
INSERT INTO dbo.MyTestProject (dateInserted) VALUES ('20200202');

测试结果:

SELECT * FROM dbo.MyTestProject;


id          dateInserted                projectNumber
----------- --------------------------- -------------
1           2019-12-06 17:27:58.8813628 19001
2           2019-12-06 17:27:58.8833638 19002
3           2019-12-06 17:27:58.8883448 19003
4           2020-01-02 00:00:00.0000000 20001
5           2020-02-02 00:00:00.0000000 20002

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多