TSQL上的触发器插入非标识表

时间:2009-06-19 19:48:45

标签: sql-server tsql

我正在研究一个需要在另一个表上重新插入数据的触发器。

目标表有一个主键INT NOT NULL WITHOUT Identity,所以我有两个选择:

  1. 计算最大值并从此处插入。
  2. 从序列表中获取最大值。
  3. 我总是创建一个带有标识的表变量,并从之前计算的值插入移位。

    CREATE TRIGGER trg
       ON  [dbo].[table] 
       AFTER INSERT
    AS
    BEGIN
        SET NOCOUNT ON;
    
        DECLARE @t TABLE (sec INT IDENTITY(1, 1), id INT)
        DECLARE @ini INT
    
        SELECT @ini = ISNULL(MAX(id), 0) FROM tableDest
        -- SELECT @ini = value FROM sequencesTable WHERE seqId = 987
    
        INSERT INTO @t (id) SELECT id FROM inserted
    
        INSERT INTO tableDest 
            (id, field1, field2) 
        SELECT @ini + t.sec, field1, field2
        FROM @t t
            JOIN inserted ON t.id = inserted.id
    
    
        -- SELECT @ini = @ini + MAX(t.sec) FROM @t
        -- UPDATE sequencesTable SET value = @ini WHERE seqId = 987
    END
    

    有没有更好的方法呢?

    先谢谢。

4 个答案:

答案 0 :(得分:2)

假设SQL 2005+,您可以使用ROW_NUMBER()

CREATE TRIGGER trg
   ON  [dbo].[table] 
   AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    INSERT INTO tableDest
        (id, field1, field2)
    SELECT
        Seed.Value + ROW_NUMBER() OVER(ORDER BY Id), 
        field1, 
        field2
    FROM Inserted
    CROSS JOIN (
       SELECT MAX(id) as Value
       FROM tableDest
    ) as Seed
END

执行CROSS JOIN而不是直接获取种子值可以使您免于MAX(Id)在获取值和插入值之间发生变化的并发问题。否则,您需要SERIALIZABLE事务来防止在读取新行后将其插入tableDest。

答案 1 :(得分:1)

只是为了澄清一下,如果我运行这个语句,它会不会在表Foo中给我一个唯一的Bar,即使同时执行多个同时语句并行执行?

INSERT INTO Foo (Bar)
  SELECT
    CASE WHEN Bar = -1 
    THEN (SELECT Seed.Value + ROW_NUMBER() OVER(ORDER BY AutoId) 
          FROM inserted CROSS JOIN (SELECT MAX(Bar) as Value FROM Foo) as Seed)
    ELSE Bar
    END

在这种情况下,是什么让语句并发安全?是因为为Bar生成新值的select嵌套在insert语句中?或者是交叉连接阻止对表Foo的同时读取访问? case语句怎么样,它在并发性方面对结果有影响吗?

谢谢!

答案 2 :(得分:0)

tableDest 真的是否需要人工主键?

此外,并发:在计算@ini的值和实际执行插入之间是否有可能在tableDest上发生其他插入?

答案 3 :(得分:0)

我想我会问一个明显的问题,为什么不在目标表上设置一个标识值? (注意,如果你这样做,请确保你没有使用@@ identity来获取源表中的标识值,因为这不是你将获得的标识值 - 你将从目标表中获取标识。 )

或者您可以使用源表中的标识作为另一个表的标识。这让我觉得这是设计的初衷。否则,可能很难将这些记录与原始数据相匹配。