2009-03-19 5 views
6

Tengo que usar activadores en MSSQL por primera vez, bien desencadenadores en general. Después de haber leído y probado esto por mí mismo, ahora me doy cuenta de que un disparador dispara por comando y no por fila insertada, eliminada o actualizada.Manejo de múltiples registros en un desencadenador de MS SQL

Todo esto son algunas estadísticas para un sistema publicitario. Nuestra tabla principal de estadísticas es bastante grande y no contiene los datos de una manera que tenga sentido en la mayoría de los casos. Contiene una fila por cada anuncio hecho clic, visto, etc. Como usuario, uno está más inclinado a querer ver esto como el día X tiene una cantidad Y de clics y una cantidad Z de vistas, y así sucesivamente. Hemos hecho esto puramente en base a una consulta SQL hasta ahora, obteniendo este tipo de informe de la tabla principal, pero a medida que la tabla ha crecido también lo hace el tiempo para que la consulta se ejecute. Debido a esto, hemos optado por usar activadores para mantener actualizada otra tabla y, por lo tanto, hacer esto un poco más fácil en el servidor SQL.

Mi problema ahora es conseguir que esto funcione con varios registros. Lo que he hecho es crear 2 procedimientos almacenados, uno para manejar el funcionamiento de un inserto y otro para eliminar. Mi desencadenador de inserción (escrito para trabajar con un solo registro) luego grafica los datos de la tabla insertada y los envía al procedimiento almacenado. El desencadenador de eliminación funciona de la misma manera y (¿obviamente?) El desencadenador de actualización hace lo mismo que eliminar + insertar.

Mi problema ahora es cómo hacer mejor esto con múltiples registros. He intentado usar un cursor, pero hasta donde he podido leer y verme a mí mismo, esto funciona muy mal. También he considerado escribir algunas "comprobaciones", como verificar si hay múltiples registros en los comandos y luego ir con el cursor, o simplemente evitar esto. De todos modos, aquí está mi solución con un cursor, y me pregunto si hay una manera de hacerlo mejor.

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 

El procedimiento almacenado es bastante grande e intenso, y no creo que hay una manera de tener que evitar el bucle a través de los registros de la tabla Insertado en una forma u otra (bueno, tal vez no, pero me Me gustaría poder leer el código también: p), así que no te voy a aburrir con eso (a menos que quieras pensar lo contrario). Así que más o menos, ¿hay una mejor manera de hacerlo, y si es así, cómo?

EDIT: Bueno, después de la solicitud, aquí está la 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 

Después de ayuda, aquí está mi resultado final, publicado en caso de que otros tienen un tema similar

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 

Se ve un poco diferente ahora porque También tuve que indexarlo por anuncio, pero gracias por la ayuda, aceleré todo desde 30 horas a 30 segundos para generar los CachedStats de mi propia tabla de estadísticas de desarrollo :)

+0

¿Puede decirnos qué hace "ProcStatInsertTrigger"? (Por cierto: no debe nombrar un sproc "Trigger", por razones bastante obvias). Si no es mucho más que insertar datos en alguna tabla, entonces hay una manera de simplificar grandemente su enfoque. – Tomalak

+0

Gracias por publicar su versión final. :) Sin embargo, no estoy seguro de que sea óptimo: usted hace muchas sub-selecciones aparentemente redundantes que se pueden extraer y calcular a partir del resultado de la combinación, en mi humilde opinión. – Tomalak

+0

ME ENCANTARÍA deshacerme de esos también. Sin embargo, como no soy un Gurú de SQL, no tengo ni idea de cómo hacerlo. Si pudieras enseñarme el camino, me encantaría optimizarlo aún más. Además, ¿sería mejor realizar un buen trabajo verificar si hay varias filas y si no solo hacerlo como antes? – kastermester

Respuesta

8

El truco con este tipo de situaciones es convertir la operación secuencial (para cada registro haga xyz) en una operación basada en conjunto (una instrucción UPDATE).

He analizado su procedimiento almacenado y he combinado sus instrucciones de ACTUALIZACIÓN por separado en una sola. Esta única declaración se puede transformar en una versión que se puede aplicar a todos los registros insertados a la vez, eliminando la necesidad de un procedimiento almacenado y, por lo tanto, la necesidad de un cursor.

EDITAR: A continuación se muestra el código que finalmente funcionó. El tiempo de ejecución para toda la operación disminuyó de "virtualmente para siempre" (para la solución original) a algo menos de un segundo, de acuerdo con los comentarios del OP. El tamaño general del código también disminuyó bastante notablemente.

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 

Las operaciones que implican la tabla CachedStats se beneficiarán enormemente de un índice de múltiples columnas sobre (Advertid, CustomerId, [Date]) (como se confirma por la OP).

+0

Ok, parece que te las arreglaste para tomar lo que pensé que sería un completo desastre y convertirlo en algo hermoso. Estoy probando esto en este momento y volveré con lo que espero que sea una respuesta aceptada muy pronto :). – kastermester

+0

He intentado esto ahora, y le he hecho algunas moderaciones (como su código obviamente no podría saber que algunos nombres de columnas entrarían en conflicto y etc.). Sin embargo, hay un problema en su comando de actualización donde se supone que solo se actualizará una cosa nueva de cada uno. Estoy tratando de resolver esto en atm. – kastermester

+0

Tengo parte de esto trabajando ahora y estoy más que esperando hacer el resto. Tendré que hacer ligeras modificaciones en el diseño de mi mesa, pero nada que rompa su solución. Planeo publicar el disparador de inserción final una vez hecho para que otros puedan ver lo que hice. ¡Gracias por tu ayuda! : D – kastermester

0

Lo primero que haría es usar un cursor FAST_FORWARD en su lugar. Como solo va de un registro al siguiente y no hace ninguna actualización, será mucho mejor para el rendimiento.

DECLARE CURSOR syntax

+0

Bueno, ese es un gran comienzo, gracias, estoy probando ese enfoque ahora para ver cuánta ganancia hay :) – kastermester

1

Dependiendo de la versión de MSSQL está ejecutando, también se debe considerar el uso de vistas indizadas para esto también. Eso podría ser un enfoque más simple que sus activadores, dependiendo de cómo se vea la consulta del informe. Vea here para más información.

Además, en su activador, debe intentar escribir sus actualizaciones en la tabla de resultados materializados como una operación basada en conjunto, no como un cursor. Escribir un desencadenador basado en el cursor podría ser simplemente mover su problema desde la consulta del informe a las inserciones de su tabla en su lugar.

+0

Yo secundaría la sugerencia de vistas indizadas, y la de usar operaciones basadas en conjuntos en el cursor. Puede ser SQL más complejo, pero será mucho más eficiente. – mwigdahl

0

Puede optimizar ligeramente la variación de su cursor haciendo las opciones FAST_FORWARD, READ_ONLY y LOCAL en el cursor. Además, está colocando el Id en el cursor y luego regresando para obtener los valores. Utilice CURRENT_OF o tírelos todos a las variables. Pero, no esperaría que estos cambios te compraran mucho.

Realmente necesita pasar a un enfoque basado en conjunto. Ese proceso almacenado es definitivamente factible en un modelo basado en conjunto, aunque puede tomar 3 o 4 declaraciones de actualización diferentes. Pero incluso 3 o 4 disparadores diferentes (1 para vistas, 1 para clics, etc.) serían mejores que el enfoque del cursor.

0

Su mejor opción es pasar a una operación basada en conjunto en el activador. No voy a escribir esto para ti al 100%, pero déjame ayudarte a empezar, y podemos ver a dónde vamos desde allí. Tenga en cuenta que estoy escribiendo esto sin tablas/esquemas y entonces no voy a validar. Esperar errores tipográficos :-)

Miremos primero sus declaraciones de actualización, por lo que puedo decir que están actualizando la misma tabla con la misma cláusula where donde la única diferencia son las columnas. Puede consolidar este se vea como:

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  

Yo aggree con usted en que esto podría ponerse feo, pero eso es una decisión que tendrá que hacer.

En cuanto a su cláusula de inserción, me gustaría manejarlo de la misma manera que ya está insertando en la tabla de la tabla insertada lo que no existe.

+0

No hay necesidad de intentar calzarlo en una sola instrucción UPDATE. Simplemente ejecute 3 o 4 instrucciones UPDATE en el desencadenador. El rendimiento, sin duda, no puede ser peor que las sentencias cursor + single UPDATE, y es probable que no sea mucho peor que una sola ACTUALIZACIÓN CASEified. –

Cuestiones relacionadas