Auto-generating value for a field based on the value of primary key, current year and previous year

不羁岁月 提交于 2020-01-16 12:02:31

问题


I have a very interesting question. I am trying to generate value for the 'Name' field based on the value of the 'ID' (primary key field).

So for example,

'ID' is 142

The 'Name' will be 19142. '19' indicating the current year.

For this, I wrote the following trigger (which works fine):

CREATE TRIGGER [dbo].[GenerateTheName]
ON [dbo].[Table1]
AFTER INSERT
AS
BEGIN

UPDATE [dbo].[Table1]

SET [Name] = (SELECT FORMAT(GETDATE(),'yy')) +
             (SELECT CAST(FORMAT([ID],'000','en-US') AS VARCHAR(4)) FROM inserted)

WHERE ID = (Select [id] FROM inserted)

END

Now, when the year changes, the id part in the value of the 'Name' field needs to be restarted from zero while the actual ID should follow the identity and be incremented by 1 as usual.

So if the last record in the Year 2019 has ID=164, the first record in the year 2020 should be:

ID: 165 Name: 20001

One way to achieve this is by creating a new table say 'table2' and storing (through a trigger) the last value of 'ID' for the current year (2019) in it. Then for the entire next year 2020, this record's data can be used as a reference.

So, if the first record in the year 2020 has ID: 165 Another trigger will subtract the only value (164) in table2 from the value of 'ID' after inserting a new record in 'table1'.

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

When the year 2020 also ends, this only record from 'table2' would be erased and again the last id for 2020 should be stored in it.

Is this the right way of solving it? Kindly suggest me the possible ways to solve it.

Thanks in advance.


回答1:


If you are willing to add another column to the table which records the current date time when the record was inserted it could all be done with 1 table and 1 trigger. Sample code -

CREATE TABLE Table1 (ID INT IDENTITY(1,1) PRIMARY KEY, Name NVARCHAR(20), CreatedDateTime DATETIMEOFFSET(7) DEFAULT SYSDATETIMEOFFSET())
GO

CREATE TRIGGER [dbo].[GenerateTheName]
ON [dbo].[Table1]
AFTER INSERT
AS
BEGIN


UPDATE [dbo].[Table1]
SET [Name] = (SELECT FORMAT(GETDATE(),'yy')) + (SELECT FORMAT((ISNULL(MAX(Id), 0) + 1), '000', 'en-US') FROM Table1 WHERE CreatedDateTime > DATEADD(yy, DATEDIFF(yy, 0, (SELECT CreatedDateTime FROM inserted)), 0)
AND CreatedDateTime < (SELECT CreatedDateTime FROM inserted))
WHERE ID = (Select [id] FROM inserted)

END

insert into table1 (createddatetime) values (sysdatetimeoffset())
insert into table1 (createddatetime) values (sysdatetimeoffset())

select * from table1 -- Gives 19001 and 19002 as name



回答2:


Sorry for responding late after your inquiry, but here is what I can offer.

From what I understood your id consists of two parts: two digits of the current year and internal unique always increasing int number. so say we started in 2019, the first Id will be 191, then 192, 193, .... 1920... etc lets say last id in year 19 was 1912345 so, when year changes to 2010, the first Id will be 2012346 and then 2012347, etc. if above assumption is correct, here is a solution for that. All you need is the table you already have and I just created a function which returns your next id and you can use it in trigger, in SP, anywhere you want.

Update Implementing another function which will reset ids on each year

CREATE TABLE [dbo].[Table1] (Id INT NOT NULL)
GO

CREATE FUNCTION dbo.PadLeft(@Number INT, @Zeros INT) 
RETURNS VARCHAR(100)
AS
BEGIN
DECLARE @Str VARCHAR(10) = CAST(@Number AS VARCHAR(10));
IF LEN(@Str) >= @Zeros
    RETURN @Str
RETURN RIGHT('000'+@Str, @Zeros);
END;
GO

CREATE FUNCTION GetNextId(@Year INT) 
RETURNS VARCHAR(100)
AS
BEGIN
    DECLARE @CurrentYear CHAR(2) = SUBSTRING(CAST(@Year AS CHAR(4)), 3, 2)
    DECLARE @LastIdOfCurrentYear INT;
    ;WITH data AS(
        SELECT CAST(Id AS VARCHAR(100)) AS Id FROM [dbo].[Table1] 
    )
    SELECT @LastIdOfCurrentYear = MAX(CAST(SUBSTRING(Id, 3, LEN(Id)-2) AS INT)) 
        FROM data
        WHERE SUBSTRING(Id, 1, 2) <= @CurrentYear
    DECLARE @NexId INT = ISNULL(@LastIdOfCurrentYear, 0) + 1;

    RETURN @CurrentYear + dbo.PadLeft(@NexId, 3)
END;
GO

CREATE FUNCTION GetNextIdWithReset(@Year INT) 
RETURNS VARCHAR(100)
AS
BEGIN
    DECLARE @CurrentYear CHAR(2) = SUBSTRING(CAST(@Year AS CHAR(4)), 3, 2)
    DECLARE @LastIdOfCurrentYear INT;
    ;WITH data AS(
        SELECT CAST(Id AS VARCHAR(100)) AS Id FROM [dbo].[Table1] 
    )
    SELECT @LastIdOfCurrentYear = MAX(CAST(SUBSTRING(Id, 3, LEN(Id)-2) AS INT)) 
        FROM data
        WHERE SUBSTRING(Id, 1, 2) = @CurrentYear
    DECLARE @NexId INT = ISNULL(@LastIdOfCurrentYear, 0) + 1;

    RETURN @CurrentYear + dbo.PadLeft(@NexId, 3)
END;
GO


INSERT [dbo].[Table1] (ID) VALUES (1912345)
SELECT 'Sequential' AS Info,
    dbo.GetNextId(2018) AS [If today is year 2018], 
    dbo.GetNextId(2019) AS [If today is year 2019], 
    dbo.GetNextId(2020) AS [If today is year 2020], 
    dbo.GetNextId(2021) AS [If today is year 2021]
SELECT 
    'With reset' AS Info,
    dbo.GetNextIdWithReset(2018) AS [If today is year 2018], 
    dbo.GetNextIdWithReset(2019) AS [If today is year 2019], 
    dbo.GetNextIdWithReset(2020) AS [If today is year 2020], 
    dbo.GetNextIdWithReset(2021) AS [If today is year 2021]

GO
DROP TABLE [dbo].[Table1];
DROP FUNCTION dbo.GetNextId;
DROP FUNCTION dbo.GetNextIdWithReset;
DROP FUNCTION dbo.PadLeft;

Here is the result of above:

Info        If today is year 2018   If today is year 2019   If today is year 2020   If today is year 2021
Sequential  18001                   1912346                 2012346                 2112346

Info        If today is year 2018   If today is year 2019   If today is year 2020   If today is year 2021
With Reset  18001                   1912346                 20001                   21001


来源:https://stackoverflow.com/questions/59193382/auto-generating-value-for-a-field-based-on-the-value-of-primary-key-current-yea

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!