Search

onze sponsors

microsoft_logo.gif


 

computrain_logo.JPG

Forum Login | Register
   Forum

 

Subject: Hulp bij een update trigger
Prev Next
You are not authorized to post a reply.

Author Messages
Stephan BussingUser is Offline

Posts:67

11-05-2007 18:25:42 Alert 
Hoi, ik heb een probleem met een update-trigger. Als ik een update uitvoer die meerdere records aanpast dan moet ik in mijn trigger een onderscheid maken welke records in een andere tabel gewijzigd moeten worden.

Voorbeeld: In tabel A worden alle prijzen met 10% verhoogt. In deze tabellen staan de ID's van verschillende artikelen. Maar het kan zijn dat Id 1 en Id 2 bij eenzelfde productgroep horen. Nu wil ik het totaal van de producten met id 1 en 2 opslaan in tabel B waarin de productgroep staat. Het probleem is echter dat er meerdere records geupdate worden en ik dus per productgroep moet totaliseren. Ik heb echter geen idee hoe ik dit voor elkaar moet krijgen. Ik weet dat de inserted-tabel de nieuwe waarde en deleted-tabel de oude waarden bevat. Maar mijn oplossingen updaten steeds teveel of helemaal niet. Moet ik soms gebruik gaan maken van een cursor in een trigger of is dit vloeken in de kerk?

Of misschien is dit helemaal niet mogelijk en moet ik per record updaten.
André KammanUser is Offline
PASS Nederland

Posts:137


11-05-2007 19:58:50 Alert 

Stephan,

Zo te zien probeer je een tabel met cumulatieve gegevens bij te houden. Ik heb een script gemaakt om een mogelijke oplossing te demonstreren.

create table Artikel(ArtikelID int, GroepID int, Prijs decimal(18,2))
create table Groep(GroepID int, sumPrijs decimal(18,2))

Create trigger tr_UpdateGroep on Artikel for Insert, Update, Delete
as
  Update Groep 
    Set sumPrijs = Artikel.Totaal
  From
  ( 
   Select 
      Artikel.GroepID, 
      Sum(Artikel.prijs) Totaal 
   From Artikel 
   Join inserted on inserted.groepID = Artikel.groepID 
   Group by Artikel.GroepID 
  ) Artikel 
  Where Groep.GroepID = Artikel.GroepID

insert into Groep(GroepID)
Select 1
union all
Select 2

insert into Artikel(ArtikelID, GroepID, Prijs)
Select 1, 1, 10.00
union all
select 2, 1, 15.10
union all
select 3, 2, 20.50
union all
select 4, 2, 19.95

Je kunt na het draaien van dit script, in een testdatabase uiteraard , de prijzen in de Artikel tabel updaten waarna de trigger het sumPrijs veld van de bijbehorende groepen zal aanpassen.
Het werkt ook als je nieuwe artikelen toevoegd of delete.

De truuk is dat je in je update statement een Select statement achter de FROM zet waardoor je een soort van view on the fly maakt. De velden die je maakt in dit statement kun je vervolgens weer gebruiken in het update statement. Zo kun je toch een GROUP BY gebruiken in combinatie met een UPDATE statement.
Ik join in mijn voorbeeld INSERTED zodat alleen de groepen die gewijzigd zijn opnieuw worden doorgerekend.

Groeten,

André

p.s.: Mocht dit niet helemaal zijn wat je zocht. Probeer dan (korte) voorbeeld scripts mee te posten waarmee iemand het scenario kan naspelen, net als ik gedaan heb in mijn uitleg.
(Mijn voorbeeld zal niet helemaal jouw situatie weergeven uiteraard, maar hopelijk kun je er wel een oplossingsrichting voor je probleem uithalen)

André KammanUser is Offline
PASS Nederland

Posts:137


11-05-2007 20:38:44 Alert 

Ik heb nog een alternatief, onderstaande trigger zal het verschil tussen inserted en deleted uitrekenen en het totaal updaten.
(Het totaal wordt dus niet steeds opnieuw uitgerekend aan de hand van alle records voor de gewijzigde groep in de ARTIKEL tabel)

Dit werkt iets beter als je bijvoorbeeld veel records hebt bij ARTIKEL.
Wel zul je als er eenmaal een foutieve waarde in staat een reparatiequery moeten draaien omdat de trigger alleen de verschillen kan verwerken.

Alter trigger tr_UpdateGroep on Artikel for Insert, Update, Delete
as
Update Groep 
   Set sumPrijs = sumPrijs + Artikel.Verschil
From

   Select 
      Groep.GroepID, 
      Sum(isNull(Inserted.Prijs, 0) - isNull(Deleted.Prijs, 0)) Verschil 
   From Groep 
   Left Join Inserted on inserted.GroepID = Groep.GroepID 
   Left join Deleted on deleted.GroepID = Groep.GroepID 
   Where Inserted.ArtikelID IS NOT NULL 
   OR Deleted.ArtikelID IS NOT NULL 
   Group by Groep.GroepID
) Artikel
Where Groep.GroepID = Artikel.GroepID

Stephan BussingUser is Offline

Posts:67

11-05-2007 21:38:28 Alert 
Hallo Andre, bedankt voor je hulp. Ik ben er mee aan het stoeien, maar helemaal lukt werkende kijrgen lukt nog niet. Jouw voorbeeld heb ik toegepast op mijn code en dan blijkt dat de Groep, om het voorbeeld aan te houden, teveel wordt geupdate. Waarschijnlijk komt het doordat ik nog een tussentabel gebruik waarin groep_id aan artikel_id gekoppeld wordt. De reden hiervan is dat een artikel bepaalde perioden tot een andere groep kan behoren. Voeg ik echter de tussentabel toe, dan worden de waarden van verdubbeld.

Create trigger tr_UpdateGroep on Artikel for Insert, Update, Delete
as
Update Groep
Set sumPrijs = Artikel.Totaal
From
(
Select
Artikel.GroepID,
Sum(Artikel.prijs) Totaal
From Artikel
Join Groep_Artikel on Artikel.Artikel_Id = Groep_Artikel_Artikel_id
Join inserted on inserted.ArtikelID = Artikel.ArtikelID
Group by Groep_Artikel.GroepID
) Artikel
Where Groep.GroepID = Artikel.GroepID

Maakt het wat meer ingewikkeld ;)

Stephan BussingUser is Offline

Posts:67

11-05-2007 22:16:20 Alert 

Hoi Andre, volgens mij ben ik eruit. De eerste test zijn hoopgevend..

Waardoor het bij mij steeds verkeerd ging, is dat ook een controle uit moet voeren op de actieve periode in het voorbeeld zou dat zijn dan alle joins uitgebreid werden met
inserted.jaar=groep.jaar en deleted.jaar=groep.jaar

Nog een kleine vraag:
Jouw eerste oplossing berekend wel steeds alles opnieuw? Klopt?
De tweede oplossing voegt alleen het verschil (positief dan wel negatief) toe. Klopt?

Ik heb vooralsnog voor de eerste oplossing gekozen.

THX

André KammanUser is Offline
PASS Nederland

Posts:137


11-05-2007 22:27:53 Alert 
Als ik het goed begrijp bevat de groep_artikel tussentabel meerdere malen hetzelfde artikel maar met steeds een andere groep. Dit komt omdat het artikel soms bij een andere groep hoort.
Hoe weet je wat de huidige groep is danwel de gewenste groep? Heeft de koppeltabel bijvoorbeeld een indicatorveld of .......

Voorbeeld :

Artikel - Groep - isCurrent - etc.
1 - 1 - 0
1- 2 - 1

In dit voorbeeld hoort artikel 1 bij groep 2.
In de join doe je dan bijvoorbeeld : JOIN ArtikelGroep on ArtikelGroep.ArtikelID = Artikel.ArtikelID AND ArtikelGroep.isCurrent = 1

Kortom, je hebt ongetwijfeld een of andere constructie in de koppeltabel gebruikt om te bepalen bij welke groep een artikel hoort op een gegeven moment. Die conditie moet je meejoinen omdat je slechts 1 record uit de koppeltabel mag halen.
(En je moet er dus ook voor zorgen dat je altijd maar 1 keer hetzelfde record hebt waarbij de isCurrent indicator op 1 staat, iets dat met unique constraints niet te doen is.)

Let op : Je tellingen kloppen niet meer als je de groep van de artikel aanpast in de koppeltabel !

Het is zaak hier goed je ontwerp in de gaten te houden, je kunt lang niet altijd "aantallen" verplaatsen naar andere "groepen".
(Niet elk bedirjf wil de omzet van bijvoorbeeld een verkoper meenemen naar de totale omzet van een andere vestiging als de verkoper een andere standplaats krijgt. De oorspronkelijke vestiging heeft "recht" op deze omzet. De omzet van de verkoper zul je dan echter bij elkaar moeten tellen vanuit de door hem behaalde omzet bij beide vestigingen etc. )


UPDATE :

Ik zie dat je net een reply hebt geplaast waarin je laat zien dat je met een soort "geldigheidsjaar' werkt. Dit maakt e.e.a. wel iets makkelijker omdat de wijzigingen dus niet te vaak plaats vinden en je eigenlijk alleen op 31 december even moet "opletten". Blijft wel dat je moet opletten of je totalen blijven kloppen als je inhoud van de koppeltabel aanpast.

Over je vraag : Mijn eerste voorbeeld rekent inderdaad alles opnieuw uit voor de groepen die gewijzigd zijn, het tweede voorbeeld past de bestaande sum aan door het verschil te verrekenen.
Stephan BussingUser is Offline

Posts:67

11-05-2007 23:38:38 Alert 
Hoi Andre, volgens mij zitten we nu op een lijn. Inderdaad, per jaar kan het artikel bij een andere groep horen. In dit voorbeeld zal in de tussentabel GroepArtikel bijvoorbeeld staan:

Groep Artikel Jaar
1 1 2006
1 2 2006
1 2 2007
5 1 2007

De history wordt op deze wijze bijgehouden. Ik denk dat de oplossing goed werkt. Overigens is het niet zo dat het updaten vaak voorkomt. Ik kon het alleen niet laten om te blijven zoeken naar een oplossing die jij nu geboden hebt. Over het algemeen wordt er per record geupdate en daar was een eenvoudige oplossing voor, maar stel dat je in een keer alle prijzen met 10% moet/wilt verhogen dan krijg je toch echt een batchupdate. Het kon er bij mij gewoon niet in dat je dat niet op kon lossen.

Ik begrijp alleen de opmerking niet over het kloppende houden van totalen. Cijfers over het voorgaande jaar worden niet meer aangepast. Alleen het huidige jaar.

De testen zulllen uit moeten wijzen of e.e.a. klopt.

Bedankt voor je reactie.
You are not authorized to post a reply.
Forums > Forums > Ontwikkelen > Hulp bij een update trigger



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