【问题标题】:Avoid hardcoding when changing values in SQL Server trigger在 SQL Server 触发器中更改值时避免硬编码
【发布时间】:2009-05-14 08:34:53
【问题描述】:

我有一个填充单个列 (PromoCode) 的 sql 服务器“而不是插入”触发器。这一切都很完美,但我不喜欢我不得不在实际的 INSERT 语句中对列进行硬编码:

CREATE TRIGGER PopulateOrderPromoCode ON Order
INSTEAD OF INSERT
AS BEGIN
    --// Get the Promo Code
    DECLARE @PromoCode int; 
    EXEC GetPromoCode @PromoCode OUTPUT;    

    --// Insert the order with the new Promo Code
    INSERT INTO Order (Id, CustomerId, PromoCode)
      SELECT Id, CustomerId, @PromoCode FROM inserted;
END

我宁愿简单地将inserted.PromoCode 中的值替换为@PromoCode,然后可以使用:

INSERT INTO Order 
  SELECT * FROM inserted;

这个可以吗?

【问题讨论】:

  • 您确定一次只能插入一行吗?如果任何人(例如,某晚修复表的 DBA)曾经在一个语句中插入多行,则所有插入的行都将被分配相同的 @PromoCode 值。

标签: sql-server triggers


【解决方案1】:

不要使用 INSTEAD OF INSERT 触发器(您必须在其中接管插入逻辑)

使用普通的 INSERT 触发器(它允许您执行 除了插入之外的操作)

这假设您可以在没有促销代码的情况下插入(允许空值)或促销代码默认为某些内容。

CREATE TRIGGER PopulateOrderPromoCode ON Order
FOR INSERT
AS 
BEGIN
    --// Get the Promo Code
    DECLARE @PromoCode int;     
    EXEC GetPromoCode @PromoCode OUTPUT;        

    --// update the order with the new Promo Code
    UPDATE Order SET PromoCode = @PromoCode
      WHERE ID IN (SELECT ID FROM inserted)
END

【讨论】:

    【解决方案2】:

    INSERTED 是一个只读临时表,可以在任何触发器中访问。你不能修改它。

    您用来执行 INSERT 的方式是最好的方式。所以,这并没有什么问题。在执行 INSERT 时指定列很好(根据我的说法)。

    【讨论】:

    • 是的,但目前在将列添加到 Order 表时必须更新触发器!理想情况下,触发器应该是透明的,因为它只作用于 Order.PromoCode 列,并且不应该对其他 Order 列感兴趣。
    【解决方案3】:

    动态 SQL 将是您唯一的其他选择。试试这个:

    CREATE TRIGGER PopulateOrderPromoCode 
    ON  Order
    INSTEAD OF INSERT
    AS 
    BEGIN    
        --// Get the Promo Code    
        DECLARE @PromoCode int;         
        EXEC GetPromoCode @PromoCode OUTPUT;      
    
        DECLARE @InsertSQL nvarchar(2000), @SelectSQL nvarchar(2000)
        SET @InsertSQL = 'INSERT INTO Order ('
        SET @SelectSQL = 'SELECT '
    
        DECLARE @CurrentCol sysname
        SET @CurrentCol = ''
    
    
    
        WHILE EXISTS (  SELECT TOP 1 QUOTENAME(name)
                        FROM    sys.syscolumns 
                        WHERE   object_name(id) = 'Order'
                        AND     name <> 'PromoCode'
                        AND     name > @CurrentCol)
        BEGIN
            SET @CurrentCol = ( SELECT TOP 1 QUOTENAME(name)
                                FROM    sys.syscolumns 
                                WHERE   object_name(id) = 'Order'
                                AND     name <> 'PromoCode'
                                AND     QUOTENAME(name) > @CurrentCol
                                ORDER BY name)
            IF @CurrentCol IS NULL Break;
    
            SET @InsertSQL = @InsertSQL + @CurrentCol + ', '
            SET @SelectSQL = @SelectSQL + @CurrentCol + ', '
        END
    
        --Finish and concatenate the strings
        SET @InsertSQL = @InsertSQL + 'PromoCode) '
        SET @SelectSQL = @SelectSQL + '''' + @PromoCode + '''' + ' FROM INSERTED'
    
        DECLARE @MasterSQL nvarchar(2000)
        SET @MasterSQL = @InsertSQL + @SelectSQL
    
        EXEC (@MasterSQL)
    END
    

    顺便说一句 - “顺序”对于表名来说是一个糟糕的选择 - 它也是 SQL 中的保留字。试试 Orders 或 OrderHeader。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-31
      • 2021-09-08
      • 1970-01-01
      • 1970-01-01
      • 2014-10-09
      相关资源
      最近更新 更多