问题
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