Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/82.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 当触发器修改列时,重新指定序列号_Sql_Sql Server_Triggers - Fatal编程技术网

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年以来一直可用。