2010-11-29 5 views
1

J'ai du mal à faire fonctionner un déclencheur TSQL correctement. Je l'ai exécuté à travers le débogueur et il ne définit pas des variables selon SQL Server Management Studio. La chose la plus foutue est que le déclencheur lui-même s'exécute correctement et qu'il n'y a pas d'erreur quand il est exécuté (il suffit de dire 'execution successful').Le déclencheur TSQL ne sauvegarde pas les variables et/ou ne s'exécute pas correctement

Le code est le suivant (il est un travail en cours .... juste obtenir mon auto familier):

USE TestDb 

IF EXISTS (SELECT name FROM sysobjects 
     WHERE name = 'OfficeSalesQuotaUpdate' AND type = 'TR') 
    DROP TRIGGER OfficeSalesQuotaUpdate 
GO 

CREATE TRIGGER OfficeSalesQuotaUpdate 
ON SalesReps 
AFTER UPDATE, DELETE, INSERT 
AS 
    DECLARE @sales_difference int, @quota_difference int 
    DECLARE @sales_original int, @quota_original int 
    DECLARE @sales_new int,   @quota_new int 

    DECLARE @officeid int 
    DECLARE @salesrepid int 

    --UPDATE(Sales) returns true for INSERT and UPDATE. 
    --Not for DELETE though.  

    IF ((SELECT COUNT(*) FROM inserted) = 0) 
     SET @salesrepid = (SELECT SalesRep FROM deleted) 
    ELSE  
     SET @salesrepid = (SELECT SalesRep FROM inserted) 

    --If you address the @salesrepid variable, it does not work. Doesn't even 
    --print out the 'this should work line. 
    PRINT 'This should work...' --+ convert(char(30), @salesrepid) 

    IF (@salesrepid = NULL) 
     PRINT 'SalesRepId is null' 
    ELSE 
     PRINT 'SalesRepId is not null' 

    PRINT convert(char(50), @salesrepid) 


    SET @officeid = (SELECT RepOffice 
         FROM SalesReps 
         WHERE SalesRep = @salesrepid) 

    SELECT @sales_original = (SELECT Sales FROM deleted) 
    SELECT @sales_new =   (SELECT Sales FROM inserted) 

    --Sales can not be null, so we'll remove this later. 
    --Use this as a template for quota though, since that can be null. 
    IF (@sales_new = null) 
    BEGIN 
     SET @sales_new = 0 
    END 

    IF (@sales_original = 0) 
    BEGIN 
     SET @sales_original = 0 
    END 

    SET @sales_difference = @sales_new - @sales_original 

    UPDATE Offices 
    SET Sales = Sales + @sales_difference 
    WHERE Offices.Office = @officeid 
GO 

Alors, des conseils? J'ai complètement perplexe sur celui-ci. Merci d'avance.

+2

tout ce qui pourrait se tromper ici, votre déclencheur ISN » t bien écrit pour faire face aux opérations multi-lignes - les tables pseudo insérées et supprimées peuvent contenir plusieurs lignes. –

+0

C'est bon, c'est juste pour la classe. Mais d'un autre côté, comment savez-vous comment avoir les deux lignes de chacune des tables virtuelles 'insérées' et 'mises à jour' lorsqu'il y a plus d'une rangée? – Nitrodist

Répondre

2

Votre principal problème semble être qu'il ya une différence entre @foo = NULL et @foo IS NULL:

declare @i int 
set @i = null -- redundant, but explicit 

if @i = null print 'equals' 
if @i is null print 'is' 

Le « Cela devrait fonctionner » déclaration d'impression ne fonctionne pas parce que concaténer une valeur NULL avec une chaîne donne une valeur NULL, et PRINT NULL n'imprime rien. Comme pour définir réellement la valeur de @salerepid, il semble très probable que la table insérée et/ou supprimée soit vide. Quelles déclarations utilisez-vous pour tester le déclencheur? Et avez-vous imprimé la valeur COUNT (*)?

Vous devriez également considérer (si ce n'est pas déjà fait) ce qui se passe si quelqu'un change plus d'une ligne à la fois. Votre code actuel suppose qu'une seule ligne est modifiée à la fois, ce qui peut être une hypothèse raisonnable dans votre environnement, mais il peut facilement se casser si quelqu'un charge en masse des données ou effectue un autre 'traitement par lots'. Enfin, vous devriez toujours mentionner votre version et votre édition de MSSQL; cela peut être pertinent pour certaines questions de syntaxe.

0

Juste une suggestion ... avez-vous essayé de mettre BEGIN et END pour encapsuler la partie 'AS' de votre trigger?

+0

Cela n'est pas requis pour un 'TRIGGER' car le' GO' signifie la fin du 'TRIGGER'. – Nitrodist

2

Vous devez remplacer le corps de la détente avec quelque chose comme ceci:

;WITH Totals AS (
    SELECT RepOffice,SUM(Sales) as Sales FROM inserted GROUP BY RepOffice 
    UNION ALL 
    SELECT RepOffice,-SUM(Sales) FROM deleted GROUP BY RepOffice 
), SalesDelta AS (
    SELECT RepOffice,SUM(Sales) as Delta FROM Totals GROUP BY RepOffice 
) 
UPDATE o 
SET Sales = Sales + sd.Delta 
FROM 
    Offices o 
     inner join 
    SalesDelta sd 
     on 
      o.Office = sd.RepOffice 

Cela correctement faire face à plusieurs lignes dans inserted et deleted. Je suppose que SalesRep est la clé primaire de la table SalesReps.


Mise à jour ci-dessus, pour faire face à ACTUALISATION changer le RepOffice d'un représentant commercial particulier (dont l'original n'a pas, presumable, obtenir correcte soit)

+0

Où est sélectionné delta? – Nitrodist

+0

@Nitrodist - c'est une nouvelle colonne introduite dans les CTE avant l'instruction update - c'est la somme de toutes les valeurs de ventes dans la table insérée (pour un RepOffice), moins la somme de toutes les valeurs de ventes dans la table supprimée (par exemple le même RepOffice) –

+0

Donc, ne devrait-il pas être «FROM Totals»? dans cette déclaration? – Nitrodist

Questions connexes