Избегайте жесткого кодирования при изменении значений в триггере SQL Server - PullRequest
1 голос
/ 14 мая 2009

У меня есть SQL Server триггер "вместо вставки", который заполняет один столбец (PromoCode). Все работает отлично, но мне не нравится тот факт, что мне пришлось жестко закодировать столбцы в реальном выражении 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

Я бы предпочел просто заменить значение внутри вставленного. PromoCode на @PromoCode и затем мог бы использовать:

INSERT INTO Order 
  SELECT * FROM inserted;

Можно ли это сделать?

Ответы [ 3 ]

2 голосов
/ 24 сентября 2009

Не используйте триггер 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
0 голосов
/ 14 мая 2009

Динамический 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.

0 голосов
/ 14 мая 2009

INSERTED - временная таблица только для чтения, доступ к которой можно получить из любого триггера Вы не можете изменить его.

И то, как вы используете INSERT, является лучшим способом. Так что в этом нет ничего плохого. Хорошо указывать столбцы при выполнении INSERT (по моему мнению).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...