2011-12-14 10 views
15

Ho il trigger in una tabella e vorrei leggere il valore UserId quando una riga viene inserita, aggiornata o cancellata. Come farlo? Il seguente codice non funziona, ottengo l'errore sul UPDATEDSQL Server: trigger come leggere il valore per Insert, Update, Delete

ALTER TRIGGER [dbo].[UpdateUserCreditsLeft] 
    ON [dbo].[Order] 
    AFTER INSERT,UPDATE,DELETE 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    DECLARE 
    @UserId INT, 

    SELECT @UserId = INSERTED.UserId FROM INSERTED, DELETED 

    UPDATE dbo.[User] SET CreditsLeft = CreditsLeft - 1 WHERE Id = @UserId 
END 
+4

È * anche * sbagliato perché possono esserci più righe in queste tabelle, quindi provare a leggere un valore in una variabile ti darà uno di quei valori di riga (quale non è definito). –

+1

Oltre a scrivere un triiger che pensa che cambierà solo una riga, che è una pratica mediocre, hai usato join impliciti che è anche un antipattern sql. Non usare mai vincoli impliciti. In questo momento hai un cross join che probabilmente non volevi.È imperdonabile scrivere questo codice quasi 20 anni dopo che i join impliciti sono stati sostituiti con i join esplicitamente migliori. – HLGEM

risposta

24

Si prega di notare che inserted, deleted significa la stessa cosa di inserted CROSS JOIN deleted e fornisce ogni combinazione di ogni riga. Dubito che questo è quello che vuoi.

Qualcosa di simile può aiutarti ad iniziare ...

SELECT 
    CASE WHEN inserted.primaryKey IS NULL THEN 'This is a delete' 
     WHEN deleted.primaryKey IS NULL THEN 'This is an insert' 
             ELSE 'This is an update' 
    END as Action, 
    * 
FROM 
    inserted 
FULL OUTER JOIN 
    deleted 
    ON inserted.primaryKey = deleted.primaryKey 


A seconda di cosa si vuole fare, è quindi fare riferimento alla tabella che ti interessa con inserted.userID o deleted.userID, ecc .


Infine, essere consapevoli che inserted e deleted sono tabelle e può contenere (e fa) più di un record.

Se si inseriscono 10 record contemporaneamente, la tabella inserted conterrà TUTTI i 10 record. Lo stesso vale per le eliminazioni e la tabella deleted. E entrambe le tabelle nel caso di un aggiornamento.


EDIT Examplee grilletto dopo PO modifica.

ALTER TRIGGER [dbo].[UpdateUserCreditsLeft] 
    ON [dbo].[Order] 
    AFTER INSERT,UPDATE,DELETE 
AS 
BEGIN 

    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    UPDATE 
    User 
    SET 
    CreditsLeft = CASE WHEN inserted.UserID IS NULL THEN <new value for a DELETE> 
         WHEN deleted.UserID IS NULL THEN <new value for an INSERT> 
                ELSE <new value for an UPDATE> 
        END 
    FROM 
    User 
    INNER JOIN 
    (
     inserted 
    FULL OUTER JOIN 
     deleted 
     ON inserted.UserID = deleted.UserID -- This assumes UserID is the PK on UpdateUserCreditsLeft 
    ) 
     ON User.UserID = COALESCE(inserted.UserID, deleted.UserID) 

END 


Se la PrimaryKey di UpdateUserCreditsLeft è qualcosa di diverso da UserID, utilizzare che nel full outer join, invece.

+1

ottima risposta, questo mi ha salvato il lavoro oggi – wondergoat77

20

Non v'è alcuna tabella dinamica updated. C'è solo inserted e deleted. Su un comando UPDATE, i vecchi dati vengono archiviati nella tabella dinamica deleted ei nuovi valori vengono memorizzati nella tabella dinamica inserted.

Si pensi a una combinazione UPDATE come DELETE/INSERT.

+0

Ho cambiato riga a SELECT @UserId = UserId FROM INSERTED, DELETED e ora ottengo errore Nome colonna ambiguo 'UserId'. – Tomas

+1

@Tomas - Guarda la mia risposta, non penso "," significa che cosa pensi che significhi. – MatBailie

+0

@Tomas è necessario specificare l'origine del campo 'UserId'. Ad esempio, fai qualcosa come 'select @UserId = inserted.UserId da inserito, cancellato' –

-4

Ecco la sintassi per creare un trigger:

CREATE TRIGGER trigger_name 
ON { table | view } 
[ WITH ENCRYPTION ] 
{ 
    { { FOR | AFTER | INSTEAD OF } { [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] } 
     [ WITH APPEND ] 
     [ NOT FOR REPLICATION ] 
     AS 
     [ { IF UPDATE (column) 
      [ { AND | OR } UPDATE (column) ] 
       [ ...n ] 
     | IF (COLUMNS_UPDATED () { bitwise_operator } updated_bitmask) 
       { comparison_operator } column_bitmask [ ...n ] 
     } ] 
     sql_statement [ ...n ] 
    } 
} 

Se si desidera utilizzare Update solo può farlo con la sezione IF UPDATE (column). Non è possibile fare ciò che stai chiedendo.

Problemi correlati