Search

onze sponsors

microsoft_logo.gif


 

computrain_logo.JPG

Forum Login | Register
   Forum

 

Subject: SQL Trigger
Prev Next
You are not authorized to post a reply.

Author Messages
Joep MulderUser is Offline

Posts:6

14-02-2008 13:42:17 Alert 
Ik heb nog niet zo veel ervaring met triggers maar ik zit met het volgende:

Kan iemand mij uitleggen hoe ik bij een een INSERT trigger een update kan uitvoeren op een van de velden die geinsert wordt?

Zoiets als:

UPDATE INSERTED
SET LineNr=-2
Henri KoppenUser is Offline

Posts:4

15-02-2008 09:07:00 Alert 
Dag Joep,

Een UPDATE op een record die je net invoegd klinkt onlogisch. Doe dan je INSERT goed dan hoef je niet te updaten. Ook kan updaten van in te voeren records bijwerkingen hebben, loops en locks veroorzaken, dus wees er voorzichtig mee.

Toevallig heb ik een situatie waarin het ook nodig heb en dat ik de UPDATE pas kan bepalen NA de insert. In dit voorbeeld wordt een versie van een voorziening gemaakt en deze krijgt een eigen volgorde. Dus volgorde 3 kan bijvoorbeeld vaker voorkomen in de tabel maar is uniek voor 1 voorziening.

Een tweede wat je altijd moet realiseren is dat ondanks dat je in de applicatie bijv. altijd maar 1 record opslaat, er ook meerdere records in 1 keer ingevoerd kunnen worden bijv. met de hand, dus dat je altijd in sets moet denken.

Het voorbeeld wat ik je nu geef is voor een specifieke situatie en gebruikt een tijdelijke tabel. Als je geen aanvullende logica hebt hun je in de trigger gewoon het statement

UPDATE INSERTED SET Veldnaam = Waarde

Of als je een berekend veld hebt

UPDATE INSERTED SET Kolom3 = Kolom1 * Kolom2
In dit voorbeeld kun je overigens beter een computed column gebruiken (SQL2005)

Maar goed, hier de trigger:
ALTER TRIGGER [dbo].[tVoorzieningVersieNummer] ON [dbo].[tblVoorzieningenVersies]

FOR INSERT

AS

SET NOCOUNT ON
/*
Version 0.01 - 07-02-2008 Henri Koppen
Description :
Genereer een versie nummer voor een voorziening

*/

DECLARE @guid UNIQUEIDENTIFIER, @Volgorde INT, @VoorzieningId UNIQUEIDENTIFIER
CREATE TABLE #vv (guid UNIQUEIDENTIFIER PRIMARY KEY, VoorzieningId UNIQUEIDENTIFIER, Volgnummer INT, Done BIT DEFAULT (0))

INSERT INTO #vv (guid, VoorzieningId)
SELECT i.guid, i.VoorzieningId
FROM INSERTED i

WHILE EXISTS (SELECT * FROM #vv WHERE Done = 0)
BEGIN
SELECT TOP 1 @guid = [guid], @VoorzieningId = VoorzieningId, @Volgorde = 0 FROM #vv WHERE Done = 0


UPDATE [dbo].[tblVoorzieningenVersies] SET Versie = ISNULL((SELECT MAX (Versie) FROM [tblVoorzieningenVersies] vv1 WHERE vv1.VoorzieningId = @VoorzieningId),0)+1 WHERE guid = @guid
UPDATE #vv SET Done = 1 WHERE [guid] = @guid

END
Henri KoppenUser is Offline

Posts:4

15-02-2008 09:10:19 Alert 
Oeps. Zit weer te slapen en kan mijn post niet wijzigen???

UPDATE INSERTED kan wellicht niet

Je doet dan UPDATE TabelWaardeTriggerOpStaat Kolom3 = Kolom2 + Kolom1 FROM TabelWaardeTriggerOpStaat t JOIN INSERTED i ON t.Sleutelveld = i.Sleutelveld

maw je gebruikt gewoon de tabel naam en joint aan de inserted.
Hugo KornelisUser is Offline

Posts:46

18-02-2008 11:37:11 Alert 
Hoi Joep,

De versie die Henri post is vrij ingewikkeld. Waarschijnlijk ingewikkelder dan jij nodig hebt.

Probeer het eens met:


CREATE TRIGGER MijnTrigger
ON MijnTabel AFTER INSERT
AS
  UPDATE   MijnTabel
  SET      LineNr = -2
  WHERE EXISTS
   (SELECT *
    FROM   inserted AS i
    WHERE  i.PrimaireSleutel = MijnTabel.PrimaireSleutel);
go

Met vriendelijke groeten,

Hugo Kornelis (SQL Server MVP)
Hugo KornelisUser is Offline

Posts:46

18-02-2008 11:41:29 Alert 
Hoi Henri,

Het is in het algemeen niet verstandig om rij voor rij te verwerken. SQL Server kan dan niet goed optimaliseren, en bovendien introduceer je onnodig extra overhead.

Als ik jouw trigger goed lees, dan moet je voor elke toegevoegde rij een waarde aan Versie toekennen die één hoger is dan de laatste waarde van Versie met dezelfde VoorzieningID. Klopt dat? Zo ja, dan kan je dat ook setbased (en dus vrijwell zeker sneller) doen. Met SQL Server 2005 kun je een CTE met ROW_NUMBER() gebruiken, met SQL Server 2000 moet je iets meer werk doen in de vorm van een correlated subquery. Een tijdelijke tabel is in elk geval niet nodig.

Heb je hier meer hulp bij nodig, post dan de tabel structuur (CREATE TABLE opdracht) en wat voorbeeld gegevens (INSERT opdrachten), want dit probleem is te ingewikkeld om uit mijn hoofd en zonder testgegevens te doen! :)

Met vriendelijke groeten,

Hugo Kornelis (SQL Server MVP)
Henri KoppenUser is Offline

Posts:4

18-02-2008 11:54:07 Alert 
Dag Hugo,

Thx voor je aanbod. Ik gebruik CTE's regelmatig, maar in dit geval was het met teveel moeite :-). Daarnaast werk ik in een team en niet iedereen is even vertrouw met een CTE aangezien die heel lastig te lezen zijn. In het voorbeeld laat ik de code zien voor als er meerdere versies van een voorziening ingevoerd worden. Dit is in principe niet mogelijk. In de oorspronkelijke trigger word de code uitgevoerd als er maar 1 inserted is, en de geposte code als er meer dan 1 regel is wat dus praktisch niet kan maar alleen is ingebouwd dat als er ineens handmatig wat gedaan wordt, de logica overeind blijft. Je veronderstelling van de logica is juist :-)
Henri KoppenUser is Offline

Posts:4

18-02-2008 11:57:47 Alert 
Overigens ben ik een gelover in SetBasesIsTheThruthPath als het gaat om database statements. Maar ben wel een praktisch ingestelde gelover ;-)

Bijna alles is SetBased op te lossen, maar het maakt het lezen van code een stuk lastiger en zeker als performance niet een steutelrol speelt dan vind ik leesbaarheid belangrijker. Maar goed, dat is persoonlijke filosofie.
You are not authorized to post a reply.
Forums > Forums > Ontwikkelen > SQL Trigger



ActiveForums 3.6
  
Copyright (c) 2012 PASS Nederland   Privacy Statement  Terms Of Use