none
Bitte um Hilfe mit Triggern RRS feed

  • Frage

  • Hallo zusammen,
    mir dreht es sich nur noch im Kopf. Wie das gehen soll.

    Könnte mir ein Kenner der Materie bitte einen Tip geben?

    Ich möchte gerne einen Trigger erstellen, der einen Wert auf einen anderen aufaddiert.

    Ich habe eine Tabelle mit den Spalten ID, SummeMinuten, Minuten
    Zu dem aktuellen Inhalt der Spalte SummeMinuten, in der DB, soll bei einem Update, der Wert der Spalte Minuten aufaddiert werden.

    Weil. Nach einem TabeleAdapter.Update, möchte ich, das die "Minuten" zu dem bestehenden Wert (in der DB) in "SummeMinuten", aufaddiert werden.
    Da unterschiedliche Benutzer einen Datensatz abspeichern können, der evtl. nicht mehr die aktuelle MinutenSumme hatt.

    Evtl. der falsche Weg, besseres ist mir nicht eingefallen.

    Gruss Peter


    Peter
    • Verschoben Thorsten Dörfler Mittwoch, 23. März 2011 14:21 Thema SQL (aus:Visual Basic (ab Version 2002 / .NET))
    Dienstag, 22. März 2011 18:31

Antworten

  • Hallo Peter,
    Ich möchte gerne einen Trigger erstellen, der einen Wert auf einen anderen aufaddiert.
    da du im VB Forum gepostet hast: Willst Du das anwendungs- oder datenbankseitig lösen? Trigger gehören eigentlich in die bzw. zur Datenbank. Falls per DBMS, welches DBMS setzt Du ein?

    Ich habe eine Tabelle mit den Spalten ID, SummeMinuten, Minuten
    Zu dem aktuellen Inhalt der Spalte SummeMinuten, in der DB, soll bei einem Update, der Wert der Spalte Minuten aufaddiert werden.

    Das würde bspw. so gehen:

    ALTER TRIGGER AktualisiereSumme ON dbo.<Tabelle> AFTER INSERT, UPDATE
    AS
    BEGIN

        SET NOCOUNT ON;

        UPDATE <Tabelle>
        SET    <Tabelle>.SummeMinuten = ISNULL( <Tabelle>.SummeMinuten, 0 ) + ISNULL( <Tabelle>.Minuten, 0 )
        FROM   <Tabelle>, inserted i
        WHERE  <Tabelle>.ID = i.ID  

    END
    GO

    Aber ehrlich gesagt finde ich das ziemlich unsinnig. Warum steht die Summe im selben Datensatz wie die einzelnen Angaben? Das macht man eigentlich eher über

    SELECT SUM( Minuten) AS SummeMinuten FROM <Tabelle>

    es sei denn, es gibt immer nur diesen einen Datensatz mit den Minuten.

    Was Du evtl. auch prüfen müsstest, ist, ob der Wert für "Minuten" sich überhaupt so verändert hat, dass die Summe aktualisiert werden soll.

    Wenn bspw. vorher 20 drin stand und ein Update setzt ebenfalls wieder 20 als Wert für Minuten, kann das sowohl bedeuten, dass effektiv wirklich nochmal 20 Minuten addiert werden sollen, es kann aber auch sein, dass ein anderes Feld aktualisiert wurde und daher keine neue SummeMinuten gebildet werden soll. Evtl. müsstest Du da dein Konzept nochmal durchgehen.

    Weil. Nach einem TabeleAdapter.Update, möchte ich, das die "Minuten" zu dem bestehenden Wert (in der DB) in "SummeMinuten", aufaddiert werden.
    Da unterschiedliche Benutzer einen Datensatz abspeichern können, der evtl. nicht mehr die aktuelle MinutenSumme hatt.

    Ehrlich gesagt ist das eine abstruse Erklärung für ein IMHO fehlerhaftes DB Design.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Dienstag, 22. März 2011 19:52
    Moderator

Alle Antworten

  • Hallo Peter,
    Ich möchte gerne einen Trigger erstellen, der einen Wert auf einen anderen aufaddiert.
    da du im VB Forum gepostet hast: Willst Du das anwendungs- oder datenbankseitig lösen? Trigger gehören eigentlich in die bzw. zur Datenbank. Falls per DBMS, welches DBMS setzt Du ein?

    Ich habe eine Tabelle mit den Spalten ID, SummeMinuten, Minuten
    Zu dem aktuellen Inhalt der Spalte SummeMinuten, in der DB, soll bei einem Update, der Wert der Spalte Minuten aufaddiert werden.

    Das würde bspw. so gehen:

    ALTER TRIGGER AktualisiereSumme ON dbo.<Tabelle> AFTER INSERT, UPDATE
    AS
    BEGIN

        SET NOCOUNT ON;

        UPDATE <Tabelle>
        SET    <Tabelle>.SummeMinuten = ISNULL( <Tabelle>.SummeMinuten, 0 ) + ISNULL( <Tabelle>.Minuten, 0 )
        FROM   <Tabelle>, inserted i
        WHERE  <Tabelle>.ID = i.ID  

    END
    GO

    Aber ehrlich gesagt finde ich das ziemlich unsinnig. Warum steht die Summe im selben Datensatz wie die einzelnen Angaben? Das macht man eigentlich eher über

    SELECT SUM( Minuten) AS SummeMinuten FROM <Tabelle>

    es sei denn, es gibt immer nur diesen einen Datensatz mit den Minuten.

    Was Du evtl. auch prüfen müsstest, ist, ob der Wert für "Minuten" sich überhaupt so verändert hat, dass die Summe aktualisiert werden soll.

    Wenn bspw. vorher 20 drin stand und ein Update setzt ebenfalls wieder 20 als Wert für Minuten, kann das sowohl bedeuten, dass effektiv wirklich nochmal 20 Minuten addiert werden sollen, es kann aber auch sein, dass ein anderes Feld aktualisiert wurde und daher keine neue SummeMinuten gebildet werden soll. Evtl. müsstest Du da dein Konzept nochmal durchgehen.

    Weil. Nach einem TabeleAdapter.Update, möchte ich, das die "Minuten" zu dem bestehenden Wert (in der DB) in "SummeMinuten", aufaddiert werden.
    Da unterschiedliche Benutzer einen Datensatz abspeichern können, der evtl. nicht mehr die aktuelle MinutenSumme hatt.

    Ehrlich gesagt ist das eine abstruse Erklärung für ein IMHO fehlerhaftes DB Design.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Dienstag, 22. März 2011 19:52
    Moderator
  • Hallo Stefan,

    zunächst vielen dank für Deine Antwort.
    Wie ich schon angedeutet hatte, bin ich mir über die Lösung nicht sicher, ob die etwas taugt.
    Mir ist nichts besseres eingefallen, deswegen möchte ich noch einmal verdeutlichen, was ich bezwecken möchte.

    Es geht um die Kostenerfassung bezüglich der aufgebrachten Zeit zu einem Projekt.

    Ich habe eine Tabelle Projekt.  (idProj, Projektname, ProjLeiter, ...)

    Eine Tabelle ProjektKosterPerGroup.  (id, idProj, idGroup, Stundensatz  , SummeKosten , Einzelbetrag )
    In dieser Tabelle werden zu dem Projekt die verschiedenen Stundensätze bezogen auf Personengruppen festgehalten.  Z.B. Techniker, Auszubildender, ...

    eine Tabelle Zeit  (id, idProjekt, Arbeitszeit, idPerson, AnfangZeit, EndeZeit, ...)
    Diese Person die einen Eintag macht, gehört einer Gruppe an, z.B. Techniker, Azszubildender, ...

    Ich will nun in der Funktion zur Eingabe der Zeit, aus der Tabelle ProjektKosterPerGroup (idProjekt, idGroup)  den Stundensatz lesen, und den Betrag (Zeit * Stundensatz) im Feld Einzelbetrag in die DB übertragen. Da jedoch der Inhalt des Feldes SummeKosten, seit dem lesen aus der DB, durch einen Eintrag eines anderen Benutzers, schon verändert haben könnte. Wollte ich das ein Trigger das Aufaddieren übernimmt. Jeweils zum aktuellen Inhalt des Feldes "SummeKosten" in der DB. Und ich somit die Kostensumme jeweils zu einem Projekt und  Gruppe, in der Tabelle ProjektKostenPerGroup habe.

    Ist das Krampf?

    Dank für Antworten.

    Gruss Peter

     

     


    Peter
    Mittwoch, 23. März 2011 06:02
  • Hallo Peter,

    "Krampf" ist es IMHO, dass Du die Summen direkt in den einzelnen Datensätzen speichern willst. Summen bildet man entweder dynamisch per SELECT SUM( <Spalte> ) FROM <Tabelle> ab oder man hat eine separate Tabelle, in der die Summen dann gespeichert werden.

    In deinem Fall würde ich das Datenbankdesign nochmal genau durchgehen, da scheint mir noch ein wenig mehr als nur die Summenfelder im Argen zu liegen.

    Der Stundensatz ist ja sicher nicht individuell pro Datensatz in "ProjektKosterPerGroup" einstellbar, oder? Eine "MischMasch" Benennung ist IMHO noch schlimmer als Denglisch. Entweder deutsch oder englisch. "ProjektKoster" (was soll das eigentlich sein? ProjektKosten?) und "PerGroup" passt irgendwie nicht. Dazu noch Spaltennamen in Deutsch, in Englisch. Chinesisch käme da sicher auch noch gut :)

    Wie gesagt, das DB Design ist sicher überarbeitungsbedürftig. Poste doch mal die Struktur der relevanten Tabellen in etwa so:

    [Projekt]
    idProj (int, IDENTITY)
    Projektname (nvarchar)
    ProjLeiter (int)

    [ProjektKosterPerGroup]
    id (int, IDENTITY)
    idProj (int, FK auf Projekt.idProj)
    idGroup (int, ???)
    ...

    Dann kann man sich das mal anschauen. (Aber kleine Warnung vorweg: Das Ergebnis könnte dann so aussehen, dass deine DB Struktur hinterher _komplett_ anders aussieht^^)

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Mittwoch, 23. März 2011 09:59
    Moderator
  • Hallo Stefan,
    ich hatte mir schon mal alle Mühe gegeben, die Antwort zu verfassen, leider sehe ich jetzt, dass nicht angekommen ist.
    So bemühe ich mich nochmals.

    Gerne möchte ich Dein Angebot annehmen, dass du ein Blick auf mein "gebastel" wirfst. Ich bin am schwimmen.
    Es handelt sich um eine Access DB die auf SQL Server portiert wurde.
    Ich möchte die Funktionalität erweitern, dass zu jedem Projekt die Kosten aufaddiert werden.


    TABLE [dbo].[tabBenutzerGruppe](
     [idBenutzerGruppe] [uniqueidentifier]  , IDENTITY
     [GruppenName] [nvarchar](50)   
    z.B.  Auszubildender, Techniker, ...

    ---------------------

    TABLE [dbo].[tabPersonal](
     [Initialen] [nvarchar](6) 
     [Name] [nvarchar](20) 
     [Vorname] [nvarchar](20) 
     ...
     [upsize_ts] [timestamp] 
     [idPersonal] [uniqueidentifier]         , IDENTITY
     [idBenutzerGruppe] [uniqueidentifier]   , FK auf tabBenutzerGruppe.idBenutzerGruppe
    Jede Person gehört auch eine BenutzerGruppe an , ist Auszubildender, Techniker, ...

    --------------------

    TABLE [dbo].[tabKostenProjektBenutzerGruppe](
     [idKostenProjektBenutzerGruppe] [uniqueidentifier]    , IDENTITY
     [idBenutzerGruppe] [uniqueidentifier]   , FK auf tabBenutzerGruppe].idBenutzerGruppe]
     [idProjekt] [uniqueidentifier]          , FK auf tabProjekte.idProjekt
     [Stundensatz] [decimal](18, 2) 
    ??      [SummeMinuten] [int] 
    ??      [SummeBetrag] [decimal](18, 2) 
     
    die Sicht auf die Tabelle stellt sich zum eingeben eines Stundensatzes, pro Projekt etwas so dar.
    GruppenName   , Stundensatz
    Auszubildender, 11
    Techniker     , 22
       ...          ...

    --------------------

    TABLE [dbo].[tabKunden](
     [Firma] [nvarchar](50) 
     [Anzeigename] [nvarchar](40) 
     [MWSTKuerzel] [nvarchar](10) 
     [KontoLeistung] [nvarchar](10) 
     [KontoSpesen] [nvarchar](10) 
     [Pauschalspesen] [bit] 
     [Quartalsspesen] [float] 
     ...
     [KundeInaktiv] [bit] NOT 
     [upsize_ts] [timestamp] 
     [idKunden] [uniqueidentifier]  , IDENTITY
     
    ----------------------

    TABLE [dbo].[tabProjekte](
     [Projektname] [nvarchar](255)
     [Projektbezeichnung] [nvarchar](255) 
     [Verantwortlicher] [nvarchar](50) 
     [Termin] [datetime] 
     [Sollstunden] [float] 
     [DefaultVerrechenbarkeit] [bit] 
     [ProjektInaktiv] [bit]
     [upsize_ts] [timestamp] NULL,
     [idProjekte] [uniqueidentifier]  ,  IDENTITY
     [idKunden] [uniqueidentifier]    ,  FK auf tabKunden.idKunden
     [ZeitDachMinuten] [int] 
     [KostenDach] [int] 

    Die Relation tabKostenProjektBenutzerGruppe.idKostenProjektBenutzerGruppe wollte ich dazu verwenden um die Kosten pro

    ----------------------

    TABLE [dbo].[tabZeit](
     [Datum] [datetime] 
     [verrechenbar] [bit] 
     [verrechnet] [bit] NOT 
     [Beschreibung] [ntext] 
     ...
     [upsize_ts] [timestamp] 
     [Verrechnungsjahr] [smallint] 
     [idZeit] [uniqueidentifier]      ,  IDENTITY
     [idProjekte] [uniqueidentifier]  , FK auf tabProjekte.idProjekt
     [idPersonal] [uniqueidentifier]  , FK auf tabPersonal.idPersonal
     [AnfangZeit] [int] 
     [EndeZeit] [int] 
     [PauseZeit] [int] 
     [ArbeitsZeit] [int] 
     [Erfassungsdatum] [datetime] 

    Mein Ansinnen, zum Aufaddieren der KostenSumme ist.
    Wenn eine neue Zeiteingabe erfolgt, bekomme ich mit idPersonal die idBenutzerGruppe.
    Mit idBenutzerGruppe und idProjekte den entsprechenden StundenSatz aus Tabelle tabKostenProjektBenutzerGruppe.
    Die Kosten sind ArbeitsZeit * StundenSatz.
    Nun sollen die Kosten auf das Projekt pro Benutzergruppe festgehalten werden.
    Eine Möglichkeit die ich sehe ist, die Kosten in tabZeit festzuhalten und Select Sum() zu bemühen.
    Dann hätte ich den Wert, nach einem TableAdapter.Fill nicht direkt zur verfügung.
    Oder in der Tabelle tabKostenProjektBenutzerGruppe.
    Da mehrere Personen zugreifen, darf es nicht sein, falls der Stundensatz geändert wird, es die aufaddierte Summe überschreibt.
    Deswegen dachte ich an einen Trigger, der zum aktuellen Datensatz in der DB den Betrag aufaddiert.
    Z.B. auch als Feld Betrag in tabKostenProjektBenutzerGruppe an die DB geschickt und gerade wieder zurückgelesen.
    Oder als Betrag in tabZeit übergeben, mit einem Trigger in tabKostenProjektBenutzerGruppe.SummeBetrag aufaddiert.
    Na, Du denkst jetzt wohl, von hinten durch die Brust in's Auge. Ich weiss es nicht besser.

    Ich hoffe, das ich es verständlich ausdrücken konnte.
    Die Tabelle tabBenutzerGruppe und tabKostenProjektBenutzerGruppe habe ich neu eingefügt.


    Vielen Dank und Gruss
    Peter

     


    Peter
    Mittwoch, 23. März 2011 16:23
  • Hallo Peter,

    doch, die Antwort ist angekommen. Die steht nur woanders, weil es im SQL Server Forum und als eigener Thread besser passt.

      http://social.msdn.microsoft.com/Forums/de-DE/sqlserverde/thread/22783e47-4528-43f0-99c2-92dd6c1c5406

    Machen wir dort weiter.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Mittwoch, 23. März 2011 16:51
    Moderator