2009-03-19 3 views
6

Мне нужно использовать триггеры в MSSQL в первый раз, а также триггеры в целом. Прочитав об этом и протестировав это, я понимаю теперь, что триггер срабатывает за команду, а не за строку, вставленную, удаленную или обновленную.Обработка нескольких записей в триггере MS SQL

Все, что касается статистики рекламной системы. Наша основная таблица статистики довольно большая и не содержит данных таким образом, что имеет смысл в большинстве случаев. Он содержит одну строку для каждого клика, просматриваемого и т. Д. В качестве пользователя более склонно хотеть просмотреть это, так как день X имеет Y количество кликов и количество просмотров и т. Д. Мы сделали это исключительно на основе SQL-запроса до сих пор, получая этот вид отчета из основной таблицы, но по мере роста таблицы время выполнения этого запроса. Из-за этого мы решили использовать триггеры для обновления другой таблицы и, следовательно, сделать это немного проще на SQL-сервере.

Моя проблема заключается в том, чтобы получить эту работу с несколькими записями. Я сделал это, чтобы создать 2 хранимых процедуры, один для обработки операции вставки и один для удаления. Мой триггер ввода (записанный для работы с одной записью) затем захватывает данные из таблицы Inserted и отправляет их в хранимую процедуру. Триггер удаления работает одинаково, и (очевидно?) Триггер обновления выполняет то же самое, что и вставка + вставка.

Моя проблема в том, как лучше всего сделать это с несколькими записями. Я пробовал использовать курсор, но насколько я мог читать и видеть себя, это работает очень плохо. Я также рассмотрел возможность написания некоторых «проверок» - как при проверке, чтобы увидеть, что в командах есть несколько записей, а затем идут с помощью курсора, а в противном случае просто избегайте этого. Во всяком случае, вот мое решение с помощью курсора, и им интересно, есть ли способ сделать это лучше?

CREATE TRIGGER [dbo].[TR_STAT_INSERT] 
    ON [iqdev].[dbo].[Stat] 
    AFTER INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @Date DATE 
    DECLARE @CampaignId BIGINT 
    DECLARE @CampaignName varchar(500) 
    DECLARE @AdvertiserId BIGINT 
    DECLARE @PublisherId BIGINT 
    DECLARE @Unique BIT 
    DECLARE @Approved BIT 
    DECLARE @PublisherEarning money 
    DECLARE @AdvertiserCost money 
    DECLARE @Type smallint 

    DECLARE InsertCursor CURSOR FOR SELECT Id FROM Inserted 
    DECLARE @curId bigint 

    OPEN InsertCursor 

    FETCH NEXT FROM InsertCursor INTO @curId 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 

     SELECT @Date = [Date], @PublisherId = [PublisherCustomerId], @Approved = [Approved], @Unique = [Unique], @Type = [Type], @AdvertiserCost = AdvertiserCost, @PublisherEarning = PublisherEarning 
     FROM Inserted 
     WHERE Id = @curId 

     SELECT @CampaignId = T1.CampaignId, @CampaignName = T2.Name, @AdvertiserId = T2.CustomerId 
     FROM Advert AS T1 
     INNER JOIN Campaign AS T2 on T1.CampaignId = T2.Id 
     WHERE T1.Id = (SELECT AdvertId FROM Inserted WHERE Id = @curId) 

     EXEC ProcStatInsertTrigger @Date, @CampaignId, @CampaignName, @AdvertiserId, @PublisherId, @Unique, @Approved, @PublisherEarning, @AdvertiserCost, @Type 

     FETCH NEXT FROM InsertCursor INTO @curId 
    END 

    CLOSE InsertCursor 
    DEALLOCATE InsertCursor 
END 

Хранимая процедура является довольно большим и интенсивным, и я не думаю, что есть способ того, чтобы избежать зацикливания по записям вставляемой таблицы в той или иной форме (хорошо, может быть, есть, но я d хотел бы иметь возможность читать код тоже: p), поэтому я не собираюсь утомлять вас этим (если вам не нравится думать иначе). Так много, есть ли лучший способ сделать это, и если да, то как?

EDIT: Ну после запроса, вот sproc

CREATE PROCEDURE ProcStatInsertTrigger 
    @Date DATE, 
    @CampaignId BIGINT, 
    @CampaignName varchar(500), 
    @AdvertiserId BIGINT, 
    @PublisherId BIGINT, 
    @Unique BIT, 
    @Approved BIT, 
    @PublisherEarning money, 
    @AdvertiserCost money, 
    @Type smallint 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 
IF @Approved = 1 
     BEGIN 
      DECLARE @test bit 

      SELECT @test = 1 FROM CachedStats WHERE [Date] = @Date AND CampaignId = @CampaignId AND CustomerId = @PublisherId 

      IF @test IS NULL 
       BEGIN 
        INSERT INTO CachedStats ([Date], CustomerId, CampaignId, CampaignName) VALUES (@Date, @PublisherId, @CampaignId, @CampaignName) 
       END 

      SELECT @test = NULL 

        DECLARE @Clicks int 
        DECLARE @TotalAdvertiserCost money 
        DECLARE @TotalPublisherEarning money 
        DECLARE @PublisherCPC money 
        DECLARE @AdvertiserCPC money 

        SELECT @Clicks = Clicks, @TotalAdvertiserCost = AdvertiserCost + @AdvertiserCost, @TotalPublisherEarning = PublisherEarning + @PublisherEarning FROM CachedStats 
        WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId 

        IF @Type = 0 -- If click add one to the calculation 
         BEGIN 
          SELECT @Clicks = @Clicks + 1 
         END 

        IF @Clicks > 0 
         BEGIN 
          SELECT @PublisherCPC = @TotalPublisherEarning/@Clicks, @AdvertiserCPC = @TotalAdvertiserCost/@Clicks 
         END 
        ELSE 
         BEGIN 
          SELECT @PublisherCPC = 0, @AdvertiserCPC = 0 
         END 
      IF @Type = 0 
       BEGIN 

        UPDATE CachedStats SET 
         Clicks = @Clicks, 
         UniqueClicks = UniqueClicks + @Unique, 
         PublisherEarning = @TotalPublisherEarning, 
         AdvertiserCost = @TotalAdvertiserCost, 
         PublisherCPC = @PublisherCPC, 
         AdvertiserCPC = @AdvertiserCPC 
        WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId 
       END 
      ELSE IF @Type = 1 OR @Type = 4 -- lead or coreg 
       BEGIN 
        UPDATE CachedStats SET 
         Leads = Leads + 1, 
         PublisherEarning = @TotalPublisherEarning, 
         AdvertiserCost = @TotalAdvertiserCost, 
         AdvertiserCPC = @AdvertiserCPC, 
         PublisherCPC = @AdvertiserCPC 
        WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId 
       END 
      ELSE IF @Type = 3 -- Isale 
       BEGIN 
        UPDATE CachedStats SET 
         Leads = Leads + 1, 
         PublisherEarning = @TotalPublisherEarning, 
         AdvertiserCost = @TotalAdvertiserCost, 
         AdvertiserCPC = @AdvertiserCPC, 
         PublisherCPC = @AdvertiserCPC, 
         AdvertiserOrderValue = @AdvertiserCost, 
         PublisherOrderValue = @PublisherEarning 
        WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId     
       END 
      ELSE IF @Type = 2 -- View 
       BEGIN 
        UPDATE CachedStats SET 
         [Views] = [Views] + 1, 
         UniqueViews = UniqueViews + @Unique, 
         PublisherEarning = @TotalPublisherEarning, 
         AdvertiserCost = @TotalAdvertiserCost, 
         PublisherCPC = @PublisherCPC, 
         AdvertiserCPC = @AdvertiserCPC 
        WHERE [Date] = @Date AND CustomerId = @PublisherId AND CampaignId = @CampaignId   
       END 
     END 
END 

После помощи, вот мой окончательный результат, размещенном в случае, если другие имеют похожую Issue

CREATE TRIGGER [dbo].[TR_STAT_INSERT] 
    ON [iqdev].[dbo].[Stat] 
    AFTER INSERT 
AS 
BEGIN 

    SET NOCOUNT ON 

    -- insert all missing "CachedStats" rows 
    INSERT INTO 
     CachedStats ([Date], AdvertId, CustomerId, CampaignId, CampaignName) 
    SELECT DISTINCT 
     CONVERT(Date, i.[Date]), i.AdvertId, i.[PublisherCustomerId], c.Id, c.Name 
    FROM 
     Inserted i 
     INNER JOIN Advert AS a ON a.Id = i.AdvertId 
     INNER JOIN Campaign AS c ON c.Id = a.CampaignId 
    WHERE 
     i.[Approved] = 1 
     AND NOT EXISTS (
       SELECT 1 
       FROM CachedStats as t 
       WHERE 
         [Date] = CONVERT(Date, i.[Date]) 
         AND CampaignId = c.Id 
         AND CustomerId = i.[PublisherCustomerId] 
         AND t.AdvertId = i.AdvertId 
     ) 

    -- update all affected records at once 
    UPDATE 
     CachedStats 
    SET 
     Clicks = 
      Clicks + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 0 
      ), 
     UniqueClicks = 
      UniqueClicks + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.[Unique] = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 0 
      ), 
     [Views] = 
      [Views] + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 2 
      ), 
     UniqueViews = 
      UniqueViews + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.[Unique] = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 2 
      ), 
     Leads = 
      Leads + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.[Unique] = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] IN (1,3,4) 
      ), 
     PublisherEarning = 
      CachedStats.PublisherEarning + ISNULL((
       SELECT SUM(PublisherEarning) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId   

      ), 0), 
     AdvertiserCost = 
      CachedStats.AdvertiserCost + ISNULL((
       SELECT SUM(AdvertiserCost) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
      ), 0), 
     PublisherOrderValue = 
      PublisherOrderValue + ISNULL((
       SELECT SUM(PublisherEarning) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 3    
      ), 0), 
     AdvertiserOrderValue = 
      AdvertiserOrderValue + ISNULL((
       SELECT SUM(AdvertiserCost) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId   
       AND s.[Type] = 3 
      ), 0), 
     PublisherCPC = 
      CASE WHEN (Clicks + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 0 
      )) > 0 THEN 
       (CachedStats.PublisherEarning + ISNULL((
       SELECT SUM(PublisherEarning) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId   
      ), 0)) -- COST^
       /(
        Clicks + (
         SELECT COUNT(*) FROM Inserted s 
         WHERE s.Approved = 1 
         AND s.PublisherCustomerId = i.PublisherCustomerId 
         AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
         AND s.AdvertId = i.AdvertId 
         AND s.[Type] = 0 
        )    
       ) --- Clicks^
      ELSE 
       0 
      END,  
     AdvertiserCPC = 
      CASE WHEN (Clicks + (
       SELECT COUNT(*) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId 
       AND s.[Type] = 0 
      )) > 0 THEN 
       (CachedStats.AdvertiserCost + ISNULL((
       SELECT SUM(AdvertiserCost) FROM Inserted s 
       WHERE s.Approved = 1 
       AND s.PublisherCustomerId = i.PublisherCustomerId 
       AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
       AND s.AdvertId = i.AdvertId   
      ), 0)) -- COST^
       /(
        Clicks + (
         SELECT COUNT(*) FROM Inserted s 
         WHERE s.Approved = 1 
         AND s.PublisherCustomerId = i.PublisherCustomerId 
         AND CONVERT(Date, s.[Date]) = CONVERT(Date, i.[Date]) 
         AND s.AdvertId = i.AdvertId 
         AND s.[Type] = 0 
        )    
       ) --- Clicks^
      ELSE 
       0 
      END  
    FROM 
     Inserted i 
    WHERE 
     i.Approved = 1 AND 
     CachedStats.Advertid = i.AdvertId AND 
     CachedStats.[Date] = Convert(Date, i.[Date]) AND 
     CachedStats.CustomerId = i.PublisherCustomerId 
    SET NOCOUNT OFF 
END 

Это выглядит несколько иначе, потому что я должен был проиндексировать его на рекламу тоже, но спасибо за помощь - ускорил все с 30 часов + до 30 секунд, чтобы генерировать CachedStats из моей собственной таблицы статистики разработки.

+0

Не могли бы вы рассказать нам, что делает «ProcStatInsertTrigger»? (BTW: Вы не должны называть sproc «Trigger», по довольно очевидным причинам). Если это не намного больше, чем вставка данных в какую-либо таблицу, то есть способ значительно упростить подход. – Tomalak

+0

Спасибо за публикацию окончательной версии. :) Однако я не уверен, что это оптимально - вы делаете много, казалось бы, лишних подвыборов, которые могут быть нарисованы и рассчитаны из результата объединения, ИМХО. – Tomalak

+0

Я бы ЛЮБЛЮ, чтобы избавиться от них. Однако, поскольку я не являюсь SQL-гуру, я понятия не имею, как это сделать. Если бы вы могли показать мне, как это сделать, я бы хотел оптимизировать его дальше. Кроме того, было бы лучше, если бы вы сделали чек, чтобы проверить, есть ли несколько строк, и если не просто так, как раньше? – kastermester

ответ

8

Трюк с такими ситуациями заключается в том, чтобы повернуть последовательную операцию (для каждой записи сделайте xyz) в операцию на основе набора (инструкция UPDATE).

Я проанализировал вашу хранимую процедуру и объединил ваши отдельные инструкции UPDATE в один. Затем этот одиночный оператор можно преобразовать в версию, которая может быть применена ко всем вставленным записям одновременно, устраняя необходимость в хранимой процедуре и, следовательно, необходимость в курсоре.

EDIT: Ниже приведен код, который мы наконец получили. В соответствии с обратной связью OP время выполнения для всей операции сократилось с «практически навсегда» (для исходного решения) на что-то менее одной секунды. Общий размер кода также заметно снизился.

CREATE TRIGGER [dbo].[TR_STAT_INSERT] 
    ON [iqdev].[dbo].[Stat] 
    AFTER INSERT 
AS 
BEGIN 
    SET NOCOUNT ON 

    -- insert all missing "CachedStats" rows 
    INSERT INTO 
    CachedStats ([Date], AdvertId, CustomerId, CampaignId, CampaignName) 
    SELECT DISTINCT 
    CONVERT(Date, i.[Date]), i.AdvertId, i.PublisherCustomerId, c.Id, c.Name 
    FROM 
    Inserted i 
    INNER JOIN Advert a ON a.Id = i.AdvertId 
    INNER JOIN Campaign c ON c.Id = a.CampaignId 
    WHERE 
    i.Approved = 1 
    AND NOT EXISTS ( 
     SELECT 1 
     FROM CachedStats 
     WHERE Advertid = i.AdvertId AND 
      CustomerId = i.PublisherCustomerId AND 
      [Date]  = CONVERT(DATE, i.[Date]) 
    ) 

    -- update all affected records at once 
    UPDATE 
    CachedStats 
    SET 
    Clicks    = Clicks    + i.AddedClicks, 
    UniqueClicks   = UniqueClicks   + i.AddedUniqueClicks, 
    [Views]    = [Views]    + i.AddedViews, 
    UniqueViews   = UniqueViews   + i.AddedUniqueViews, 
    Leads    = Leads    + i.AddedLeads, 
    PublisherEarning  = PublisherEarning  + ISNULL(i.AddedPublisherEarning, 0), 
    AdvertiserCost  = AdvertiserCost  + ISNULL(i.AddedAdvertiserCost, 0), 
    PublisherOrderValue = PublisherOrderValue + ISNULL(i.AddedPublisherOrderValue, 0), 
    AdvertiserOrderValue = AdvertiserOrderValue + ISNULL(i.AddedAdvertiserOrderValue, 0) 
    FROM 
    (
    SELECT 
     AdvertId, 
     CONVERT(DATE, [Date]) [Date], 
     PublisherCustomerId, 
     COUNT(*) NumRows, 
     SUM(CASE WHEN Type IN (0)      THEN 1 ELSE 0 END) AddedClicks, 
     SUM(CASE WHEN Type IN (0)  AND [Unique] = 1 THEN 1 ELSE 0 END) AddedUniqueClicks, 
     SUM(CASE WHEN Type IN (2)      THEN 1 ELSE 0 END) AddedViews, 
     SUM(CASE WHEN Type IN (2)  AND [Unique] = 1 THEN 1 ELSE 0 END) AddedUniqueViews, 
     SUM(CASE WHEN Type IN (1,3,4) AND [Unique] = 1 THEN 1 ELSE 0 END) AddedLeads, 
     SUM(PublisherEarning)          AddedPublisherEarning, 
     SUM(AdvertiserCost)          AddedAdvertiserCost, 
     SUM(CASE WHEN Type IN (3) THEN PublisherOrderValue ELSE 0 END) AddedPublisherOrderValue, 
     SUM(CASE WHEN Type IN (3) THEN AdvertiserOrderValue ELSE 0 END) AddedAdvertiserOrderValue 
    FROM 
     Inserted 
    WHERE 
     Approved = 1 
    GROUP BY 
     AdvertId, 
     CONVERT(DATE, [Date]), 
     PublisherCustomerId 
    ) i 
    INNER JOIN CachedStats cs ON 
     cs.Advertid = i.AdvertId AND 
     cs.CustomerId = i.PublisherCustomerId AND 
     cs.[Date]  = i.[Date] 

    SET NOCOUNT OFF 
END 

операция, связанная с CachedStats таблицы будет извлечь большую пользу из одного индекса нескольких столбцов над (Advertid, CustomerId, [Date]) (как это было подтверждено OP).

+0

Ок, похоже, вам удалось взять то, что, как я думал, было бы полным беспорядком и превратить его во что-то красивое - я сейчас тестирую это и вернусь с тем, что, как я ожидаю, будет принятым ответом очень скоро :). – kastermester

+0

Я пробовал это сейчас, и я сделал несколько модераций к нему (например, ваш код, очевидно, не мог знать, что некоторые имена столбцов конфликтуют и т. Д.). Проблема, хотя и находится в вашей команде обновления, где предполагается, что обновляется только одна новая вещь. Однако я пытаюсь разобраться в этом. – kastermester

+0

У меня есть часть этой работы сейчас, и я больше ожидаю, чтобы все остальное. Мне нужно будет внести небольшие изменения в мой макет таблицы, но ничего не сломает ваше решение. Я планирую опубликовать окончательный триггер триггера, сделанный с ним, чтобы другие могли видеть, что я сделал. Спасибо за помощь! : D – kastermester

0

Первое, что я хотел бы сделать, это использовать вместо этого курсор FAST_FORWARD. Поскольку вы переходите от одной записи к другой и не делаете никаких обновлений, это будет намного лучше для производительности.

DECLARE CURSOR syntax

+0

Хорошо, что это отличное начало, спасибо, я сейчас пытаюсь понять, как увеличить выигрыш :) – kastermester

1

В зависимости от того, какая версия MSSQL вы работаете, вы должны также рассмотреть возможность использования индексированных представлений для этого, как хорошо. Это может быть очень простой подход, чем ваши триггеры, в зависимости от того, как выглядит запрос отчета. См. here для получения дополнительной информации.

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

+0

Я бы предпочел бы предложение индексированных представлений, а другое - использовать операции на основе набора в курсоре. Это может быть более сложный SQL, но он будет более эффективным. – mwigdahl

0

Вы можете немного оптимизировать изменение курсора, выполнив FAST_FORWARD, READ_ONLY и LOCAL на курсоре. Кроме того, вы вытаскиваете идентификатор в свой курсор, а затем возвращаетесь назад, чтобы получить значения. Либо используйте CURRENT_OF, либо бросайте их в переменные. Но я бы не ожидал, что эти изменения будут покупать вас много.

Вам действительно нужно перейти к набору основанного подхода. Этот хранимый процесс, безусловно, можно выполнять в модели, основанной на наборе, хотя может потребоваться 3 или 4 разных оператора обновления. Но даже три или три разных триггера (1 для просмотров, 1 для кликов и т. Д.) Были бы лучше, чем подход курсора.

0

Лучше всего перейти на операцию, основанную на наборе. Я не буду писать это для вас на 100%, но позвольте мне начать, и мы можем видеть, куда мы идем оттуда. Имейте в виду, что я пишу это без таблиц/схем, и поэтому я не буду проверять. Expect Typos :-)

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

UPDATE CachedStats SET 
     /* Basically we are going to set the counts based on the type inline in the update clause*/ 

    Leads= CASE WHEN (@Type = 1 OR @Type = 4 OR @Type=3) THEN Leads + 1 ELSE LEADS END, 
     Clicks=CASE WHEN (@Type=0) THEN Clicks+1 ELSE Clicks END, 
    Views=CASE WHEN (@Type=4) THEN Views+1 ELSE Views END, 
     PublisherEarning = @PublisherEarning + PublisherEarning, 
     AdvertiserCost = @AdvertiserCost +AdvertiserCost, 
FROM CachedStats CS 
INNER JOIN Inserted INS 
    ON CS.Date=Inserted.Date AND CS.CustomerId=Ins.PublisherId AND CS.CampaignId=Ins.CampaignId  

Я aggree с вами, что это может получить уродливые, но это решение, которое вы должны будете сделать.

Что касается вашего предложения вставки, я бы обработал его так же, как вы уже вставляете в таблицу из таблицы Inserted, которая еще не существует.

+0

Нет необходимости пытаться вставлять его в один оператор UPDATE. Просто запустите 3 или 4 оператора UPDATE в триггере. Производительность, конечно, не может быть хуже, чем курсор + один оператор UPDATE - и, вероятно, будет не намного хуже, чем один CASEified UPDATE. –

Смежные вопросы