2009-05-14 2 views
1

У меня есть SQL-сервер вместо триггера "insert", который заполняет один столбец (PromoCode). Это все работает отлично, но мне не нравится тот факт, я должен был жёстко столбцы в действительности заявления INSERT:Избегайте жесткого кодирования при изменении значений в триггере SQL Server

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; 

Это можно сделать?

+1

Вы не уверены, что будете вставлять только одну строку за раз? Если кто-нибудь (скажем, администратор базы данных за одну ночь) добавляет несколько строк в один оператор, всем вставленным строкам будет присвоено то же значение @PromoCode. –

+0

Массовая копия кого-нибудь? – NotMe

ответ

0

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

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

+0

Верно, но в настоящее время триггер должен обновляться, когда столбцы добавляются в таблицу заказов! В идеале триггер будет прозрачным, поскольку он действует только на столбец Order.PromoCode и не должен интересоваться другими столбцами Order. – user97280

-2

Dynamic 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 

BTW - «порядок» является плохим выбором для имени таблицы - это также зарезервированное слово в SQL. Попробуйте заказы или OrderHeader.

2

Не использовать ВМЕСТО INSERT триггера (в которой вы должны взять на себя логику вставки)

Используйте обычный INSERT триггер (что позволяет сделать материал в дополнение к вставка,)

Это предполагает, что вы можете вставить без промо-кода (разрешает null) или промо-код по умолчанию.

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 
Смежные вопросы