Sql 当触发器修改列时,重新指定序列号
我有一个存储一些数据的表。每个数据行都有按组织和年份分组的序列号。下表的结构如下Sql 当触发器修改列时,重新指定序列号,sql,sql-server,triggers,Sql,Sql Server,Triggers,我有一个存储一些数据的表。每个数据行都有按组织和年份分组的序列号。下表的结构如下 | ID | Seq_num | Organisation | Year | |----|---------|--------------|------| | 1 | 1 | A | 2017 | | 2 | 2 | A | 2017 | | 3 | 3 | A | 2017 | | 4 | 1
| ID | Seq_num | Organisation | Year |
|----|---------|--------------|------|
| 1 | 1 | A | 2017 |
| 2 | 2 | A | 2017 |
| 3 | 3 | A | 2017 |
| 4 | 1 | A | 2018 |
| 5 | 2 | A | 2018 |
| 6 | 3 | A | 2018 |
| 7 | 1 | A | 2019 |
| 8 | 2 | A | 2019 |
| 9 | 4 | A | 2017 |
这张桌子我有两个箱子:
1为新行分配序列号
2修改列年份时重新分配序列号
对于第一种情况,我只需从组织和年份的序号中选择max,如下所示:
对于第二种情况,如果年份被修改,我需要重新分配Seq_num。例如,如果我将id=5的年份从2018年更改为2017年,则Seq_num应从2变为4,因为4等于2017年集团+1的最大数量。
无需重新分配其他值。我该如何得到我需要的 这条评论太长了 为什么要麻烦存储序列号?您可以使用以下方法动态生成它:
select t.*,
row_number() over (partition by organization, year order by id) as seq_num
from t;
您可能希望将数据存储在表中的原因有很多,例如,如果表非常大,并且性能是一个问题的话。或者,如果您可能要删除行并希望保留原始序列号
然而,对于一个包含数千行和数千列的表,例如year和organization,这让我觉得该表并没有那么大,动态计算是非常可行的,而且要简单得多。这太长了,无法发表评论 为什么要麻烦存储序列号?您可以使用以下方法动态生成它:
select t.*,
row_number() over (partition by organization, year order by id) as seq_num
from t;
您可能希望将数据存储在表中的原因有很多,例如,如果表非常大,并且性能是一个问题的话。或者,如果您可能要删除行并希望保留原始序列号
然而,对于一个包含数千行和数千列的表,例如year和organization,这让我觉得该表并没有那么大,动态计算是非常可行的,而且要简单得多。我讨厌触发器,但是,似乎总是会出现一个用例。我仍然会查看这是否是可以在表的更新存储过程中控制的内容 如果您想要一个触发器解决方案,那么我将创建一个仅更新的触发器,并遍历所有插入的记录,并更新其中修改了年份值的记录。作为一个副作用,您创建了一个不透明的业务规则,如果有人干扰触发器,您可能会遇到一个调用触发器的触发器,这是不好的
CREATE TRIGGER [dbo].[trMyTableModified]
ON [dbo].[MyTable]
AFTER UPDATE
AS BEGIN
SET NOCOUNT ON;
DECLARE @ID INT, @CurrentValueYear INT, @PriorValueYear INT, @OrganizationID INT
DECLARE X CURSOR FORWARD_ONLY READ_ONLY LOCAL FOR
SELECT ID,Year,OrganizationID FROM INSERTED
OPEN X
FETCH NEXT FROM X INTO @ID,@CurrentValueYear,@OrganizationID
WHILE @@FETCH_STATUS = 0 BEGIN
SELECT @PriorValueYear = Year FROM DELETED WHERE ID=@ID
IF(@PriorValueYear<>@CurrentValueYear) BEGIN
UPDATE MyTable
SET
MyTable.Seq_Num =
(
SELECT MAX(Seq_Num)
FROM MyTable T
WHERE
T.Organization=@OrganizationID
AND
T.Year=@CurrentValueYear
) + 1
WHERE
MyTable.ID= @ID
END
END
CLOSE X
DEALLOCATE X
END
一个更新查询用于执行检查和更新
这没有经过测试,但是,您可以在一个查询中检查更改、提取max序列并执行更新。它可能证明更有效。插入和删除的记录应始终包含相同数量的记录,即使是由merge语句触发,因为合并将导致对每个操作、更新、删除
WITH YearChanges AS
(
SELECT I.ID,I.Year,I.OrganizationID
FROM
INSERTED I
INNER JOIN DELETED D ON D.ID=I.ID AND D.Year<>I.Year -- Ignore updates where year has not changed
),
WITH MaxSeq AS
(
SELECT Year,OrganizationID,NextSeqenceNumber = MAX(Seq_Num ) + 1
FROM
MyTable T
INNER JOIN YearChanges YC ON YC.OrganizationID = T.OrganizationID AND YC.Year=T.Year
GROUP BY
Year, OrganizationID
)
UPDATE
MyTable T
SET
Seq_Num = YC.NextSeqenceNumber
FROM
YearChanges YC
INNER JOIN MaxSeq MS ON MS.Year=YC.Year AND MS.OrganizationID=YC.OrganizationID
WHERE
T.ID=YC.ID
我讨厌触发器,然而,用例似乎总是突然出现。我仍然会查看这是否是可以在表的更新存储过程中控制的内容 如果您想要一个触发器解决方案,那么我将创建一个仅更新的触发器,并遍历所有插入的记录,并更新其中修改了年份值的记录。作为一个副作用,您创建了一个不透明的业务规则,如果有人干扰触发器,您可能会遇到一个调用触发器的触发器,这是不好的
CREATE TRIGGER [dbo].[trMyTableModified]
ON [dbo].[MyTable]
AFTER UPDATE
AS BEGIN
SET NOCOUNT ON;
DECLARE @ID INT, @CurrentValueYear INT, @PriorValueYear INT, @OrganizationID INT
DECLARE X CURSOR FORWARD_ONLY READ_ONLY LOCAL FOR
SELECT ID,Year,OrganizationID FROM INSERTED
OPEN X
FETCH NEXT FROM X INTO @ID,@CurrentValueYear,@OrganizationID
WHILE @@FETCH_STATUS = 0 BEGIN
SELECT @PriorValueYear = Year FROM DELETED WHERE ID=@ID
IF(@PriorValueYear<>@CurrentValueYear) BEGIN
UPDATE MyTable
SET
MyTable.Seq_Num =
(
SELECT MAX(Seq_Num)
FROM MyTable T
WHERE
T.Organization=@OrganizationID
AND
T.Year=@CurrentValueYear
) + 1
WHERE
MyTable.ID= @ID
END
END
CLOSE X
DEALLOCATE X
END
一个更新查询用于执行检查和更新
这没有经过测试,但是,您可以在一个查询中检查更改、提取max序列并执行更新。它可能证明更有效。插入和删除的记录应始终包含相同数量的记录,即使是由merge语句触发,因为合并将导致对每个操作、更新、删除
WITH YearChanges AS
(
SELECT I.ID,I.Year,I.OrganizationID
FROM
INSERTED I
INNER JOIN DELETED D ON D.ID=I.ID AND D.Year<>I.Year -- Ignore updates where year has not changed
),
WITH MaxSeq AS
(
SELECT Year,OrganizationID,NextSeqenceNumber = MAX(Seq_Num ) + 1
FROM
MyTable T
INNER JOIN YearChanges YC ON YC.OrganizationID = T.OrganizationID AND YC.Year=T.Year
GROUP BY
Year, OrganizationID
)
UPDATE
MyTable T
SET
Seq_Num = YC.NextSeqenceNumber
FROM
YearChanges YC
INNER JOIN MaxSeq MS ON MS.Year=YC.Year AND MS.OrganizationID=YC.OrganizationID
WHERE
T.ID=YC.ID
我的解决方案。更新后触发器中有两个update语句。相当慢,但它可以工作:
所以,若年份发生变化,当前Seq_num将变为NULL,然后第二个UPDATE语句为Seq_num分配新值。更新后触发器中有两个update语句。相当慢,但它可以工作:
因此,如果年份发生变化,当前Seq_num变为NULL,那么第二个UPDATE语句为Seq_num分配新值该表非常大,我们必须保持原始序列号该表非常大,我们必须使用最大窗口来保持原始序列号良好的作业。我需要养成这样的习惯,把它作为一个用例,因为它从2012年就开始使用了。我需要养成这样的习惯,将其作为一个用例,因为它自2012年以来一直可用。