Announcement

Collapse
No announcement yet.

Fehlschlagendes UPDATE abfangen - geht das?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Fehlschlagendes UPDATE abfangen - geht das?

    Hallo alle zusammen,

    bin neu hier, mein Name ist Carsten.

    Hier gleich eine Frage:

    Ich will bei einem UPDATE mit Angabe des Primärschlussels den Fall abfangen, daß der spezifizierte Satz nicht gefunden wurde, und ihn automatisch einfügen. Also grob so etwas:

    UPDATE tbl SET fld = <x> WHERE pkey = <y>

    und wenn pkey = <y> nicht existiert, soll automatisch

    INSERT INTO tbl (pkey) VALUES (<y>)

    erfolgen.

    Wäre ja elegant mit einem Trigger. Problem dabei ist, daß in diesem Fall nicht nur deleted leer ist, sondern auch inserted. Ist auch nachvollziehbar, denn wenn kein Satz gefunden wurde, wird auch keine Änderung durchgeführt.

    Die Frage ist nun: Habe ich in einem solchen Fall eine andere Möglichkeit, an <y> zu kommen? Eigentlich müßte es eine geben, aber ich komm' nicht drauf'.

    Vielen Dank im Voraus,

    Carsten

  • #2
    Hallo Carsten,

    habe ich das richtig verstanden, bei Dir zündet ein UPDATE Trigger auch dann, wenn kein Datensatz betroffen ist? Das verwundert mich gerade etwas ...

    Für Trigger gibt es keine "Übergabe-Parameter" o.ä., nur die virtuellen Tabellen INSERTED und DELETED.

    Das was Du da machen möchtest, ist eigentlich nur mit einer StoredProcedure erledigen, wo Du <x> und <y> übergibts; ist über den PK <y> nicht vorhanden, kannst Du <Y> zusammen mit <x> einfügen.

    Das könntest Du z.B. so erledigen
    IF EXISTS (SELECT pkey FROM tbl where pkey = <y>)
    UPDATE ....
    ELSE
    INSERT .....


    Olaf
    Olaf Helper

    <Blog> <Xing>
    * cogito ergo sum * errare humanum est * quote erat demonstrandum *
    Wenn ich denke, ist das ein Fehler und das beweise ich täglich

    Comment


    • #3
      Originally posted by O. Helper View Post
      Hallo Carsten,
      habe ich das richtig verstanden, bei Dir zündet ein UPDATE Trigger auch dann, wenn kein Datensatz betroffen ist? Das verwundert mich gerade etwas ...
      Sorry, da war ich etwas unspezifisch. Ein normaler (AFTER) UPDATE-Trigger natürlich nicht - aber ein INSTEAD OF UPDATE-Trigger schon.

      Originally posted by O. Helper View Post
      Für Trigger gibt es keine "Übergabe-Parameter" o.ä., nur die virtuellen Tabellen INSERTED und DELETED.
      Schon klar. Aber ich vermute, daß es trotzdem über irgendwelche Systemsichten o.Ä. möglich wäre.

      Originally posted by O. Helper View Post
      Das was Du da machen möchtest, ist eigentlich nur mit einer StoredProcedure erledigen, wo Du <x> und <y> übergibts; ist über den PK <y> nicht vorhanden, kannst Du <Y> zusammen mit <x> einfügen.
      Auch diese Variante ist mir bereits bekannt, aber aus bestimmten Gründen will ich die möglichst vermeiden.

      Trotzdem Danke für die Antwort,

      Carsten

      Comment


      • #4
        Also Carsten, da machst du etwas falsch, denn im INSTEAD OF INSERT stehen die Werte sehr wohl in der Pseudotabelle "inserted" zur Verfügung. Vielleicht greifst du falsch darauf zu oder auf ein falsches Feld ... Ich habe es gerade probiert, bei mir klappt's jedenfalls.

        bye,
        Helmut

        [edit] uuups, übersehen ... die willst ja ein INSTEAD OF UPDATE - da kommt tatsächlich nichts in inserted/deleted daher. Aber mache es dann andersrum. Also einfach immer ein Insert ausführen und der INSTEAD OF INSERT-Trigger (der hat ja die Werte in inserted) macht ein Insert wenn es den Satz nicht gibt, ansonsten ein update :-))

        [edit 2] aaargh, zur Richtigstellung: ein INSTEAD OF UPDATE-Trigger hat sehr wohl die Werte in inserted stehen, er wird aber nur ausgeführt, wenn es wirklich was zu updaten gibt, sprich, versuche ich ein Update auf einen nicht existierenden Satz, wird der Trigger nicht aktiv ...
        Zuletzt editiert von hwoess; 09.01.2008, 17:15.

        Comment


        • #5
          Originally posted by hwoess View Post
          [edit] uuups, übersehen ... die willst ja ein INSTEAD OF UPDATE - da kommt tatsächlich nichts in inserted/deleted daher. Aber mache es dann andersrum. Also einfach immer ein Insert ausführen und der INSTEAD OF INSERT-Trigger (der hat ja die Werte in inserted) macht ein Insert wenn es den Satz nicht gibt, ansonsten ein update :-))

          [edit 2] aaargh, zur Richtigstellung: ein INSTEAD OF UPDATE-Trigger hat sehr wohl die Werte in inserted stehen, er wird aber nur ausgeführt, wenn es wirklich was zu updaten gibt, sprich, versuche ich ein Update auf einen nicht existierenden Satz, wird der Trigger nicht aktiv ...
          Die Lösung hab' ich auch schon angedacht, sie ist aber in der gegebenen Situation auch nicht gut.

          Und was den INSTEAD OF UPDATE-Trigger betrifft - der wird sehr wohl aktiv, nur hat er eben in dem Fall auch in INSERTED keine rows. Das läßt sich recht gut an einem Beispiel erkennen.

          Aber trotzdem Danke für Deine Hilfe.
          Zuletzt editiert von LXP; 09.01.2008, 18:08.

          Comment


          • #6
            Je länger ich darüber nachdenke, desto mehr wird mir klar, dass in dem Fall eines nicht stattfindenden Updates einfach nichts in "inserted", "deleted" oder sonstwo stehen kann. Was sollte denn der Server zB tun bei

            update tabelle set vorname = 'X' where vorname like 'A%' and DAY(geburtstag) = 7

            bye,
            Helmut

            Comment


            • #7
              Originally posted by hwoess View Post
              Je länger ich darüber nachdenke, desto mehr wird mir klar, dass in dem Fall eines nicht stattfindenden Updates einfach nichts in "inserted", "deleted" oder sonstwo stehen kann. Was sollte denn der Server zB tun bei

              update tabelle set vorname = 'X' where vorname like 'A%' and DAY(geburtstag) = 7
              Also, daß DELETED leer ist, wenn kein betroffener Satz gefunden wird, ist klar. Ich hätte mir durchaus vorstellen können und es sowohl für sinnvoll als auch wünschenswert erachtet, wenn INSERTED die übergebenen Werte enthält.
              An anderer Stelle würde ich es auf jeden Fall erwarten.

              Wenn man in Deinem Beispiel also mal davon ausgeht, daß kein Satz existiert, der die angegebenen Kriterien erfüllt, würde ich Folgendes erwarten:

              0 Sätze in DELETED

              1 Satz in INSERTED, mit INSERTED.vorname = 'X', alle anderen Felder = NULL

              Eigentlich ganz schlüssig.
              Zuletzt editiert von LXP; 13.01.2008, 05:06.

              Comment


              • #8
                Na und wie machst du das mit dem zweiten Teil, also wo der Tag des Geburtstages 7 ist ??
                Es gibt hier keine halben Sachen, entweder lässt sich etwas ganz oder gar nicht umsetzen, daher erscheint es mir nur logisch, nichts in inserted zu haben, da ja nicht passiert ist.
                Aber vielleicht eine andere Variante: schaue dir mal DBCC INPUTBUFFER an. Damit kann man auf das Statement zugreifen. Allerdings musst du es dann selber parsen und herausfinden, was zu tun ist. Ausserdem braucht der Trigger/Aufrufer dafür Sysadmin- und ViewServerState-Rechte, sonst geht's auch nicht. Habe selber noch nichts in dieser Richtung gemacht und kann dir daher keine weiteren Tipps dazu geben, aber vielleicht kannst du ja was damit anfangen.

                bye,
                Helmut

                Comment


                • #9
                  Originally posted by hwoess View Post
                  Na und wie machst du das mit dem zweiten Teil, also wo der Tag des Geburtstages 7 ist ??
                  Wo bitte ist das Problem? DAY gibt die Ordinalzahl des Tages im Monat zurück, also für heute, den 14.1.08 den Wert 14.
                  Oder meinst Du DATEPART(dw, <date>)?

                  Originally posted by hwoess View Post
                  Es gibt hier keine halben Sachen, entweder lässt sich etwas ganz oder gar nicht umsetzen, daher erscheint es mir nur logisch, nichts in inserted zu haben, da ja nicht passiert ist.
                  Das Eine erscheint mir nahezu ebenso logisch wie das Andere, aber letztlich zählen ja nur die Fakten, schon richtig.

                  Originally posted by hwoess View Post
                  Aber vielleicht eine andere Variante: schaue dir mal DBCC INPUTBUFFER an. Damit kann man auf das Statement zugreifen. Allerdings musst du es dann selber parsen und herausfinden, was zu tun ist. Ausserdem braucht der Trigger/Aufrufer dafür Sysadmin- und ViewServerState-Rechte, sonst geht's auch nicht. Habe selber noch nichts in dieser Richtung gemacht und kann dir daher keine weiteren Tipps dazu geben, aber vielleicht kannst du ja was damit anfangen.
                  Das ist in der Tat eine gute Idee, danke!

                  Comment


                  • #10
                    Hallo Carsten,

                    DBCC INPUTBUFFER gibt Dir nur die ersten 255 Zeichen des Statements zurück, da könnte also einiges fehlen.

                    Olaf.

                    P.S.:
                    Was würdest Du den in der INSERTED Tabelle bei folgendem Script erwarten? Nicht das ich die Discussion übertreiben oder Helmut Recht geben wollte ;-)

                    UPDATE Tabelle
                    SET Feld1 = Feld1
                    WHERE 1 = 2
                    Olaf Helper

                    <Blog> <Xing>
                    * cogito ergo sum * errare humanum est * quote erat demonstrandum *
                    Wenn ich denke, ist das ein Fehler und das beweise ich täglich

                    Comment


                    • #11
                      Hallo Olaf,

                      woher hast du die Begrenzung mit den 255 Zeichen? Ich habe es mal ausprobiert (SQL 2005) und mein Statement mit über 3400 Zeichen war kein Problem, habe ich von INPUTBUFFER vollständig bekommen.

                      bye,
                      Helmut

                      PS:
                      Carsten, noch eine kurze Bemerkung zu DAY(datum) - ist genau das gleiche wie DATEPART(d,datum), nur kürzer :-))
                      Zuletzt editiert von hwoess; 14.01.2008, 17:30.

                      Comment


                      • #12
                        Hallo Hellmut,

                        in der Doku zum SQL 2000 (weil wir halt in dem Forum gerade sind und nichts anderweitig erwähnt wurde) ist das EventInfo mit nvarchar(255) definiert.
                        Für den SQL 2005 ist es in der Tat mit nvarchar(4000) definiert.

                        Olaf
                        Olaf Helper

                        <Blog> <Xing>
                        * cogito ergo sum * errare humanum est * quote erat demonstrandum *
                        Wenn ich denke, ist das ein Fehler und das beweise ich täglich

                        Comment


                        • #13
                          Ach ja, habe es gerade bemerkt, dass sich das nicht im SQL2005er-Forum abspielt

                          bye,
                          Helmut

                          Comment


                          • #14
                            Originally posted by hwoess View Post
                            Ich habe es mal ausprobiert (SQL 2005) und mein Statement mit über 3400 Zeichen war kein Problem, habe ich von INPUTBUFFER vollständig bekommen.
                            Hi Helmut,

                            nur 'ne Bemerkung meinerseits: Wenn man einzelne Statements mit 3400 Zeichen oder mehr absetzen muß, ist es höchste Zeit, aufzuräumen und das Datenmodell zu überarbeiten.

                            Originally posted by hwoess View Post
                            Carsten, noch eine kurze Bemerkung zu DAY(datum) - ist genau das gleiche wie DATEPART(d,datum), nur kürzer :-))
                            Du hast meine Rückfrage nicht verstanden. Ich zitiere:

                            --- schnipp ----

                            Syntax
                            DAY ( date )

                            Argumente
                            date

                            Ein Ausdruck vom Typ datetime oder smalldatetime.

                            Rückgabetypen
                            int

                            Hinweise
                            Diese Funktion entspricht DATEPART(dd, date).

                            --- schnapp ---

                            Dein Beispiel ließ vermuten, daß Du mit DAY(x) = 7 automatisch false zu erhalten glaubtest, und das stimmt eben nicht, weil DAY(date) den Tag des Monats liefert. Aber DATEPART(dw, date) liefert den Wochentag und kann, wenn ich mich recht erinnere, je nach Einstellung nur Werte zwischen 0 und 6 zurückgeben.

                            Oder wo sonst soll das Problem mit DAY(x) = 7 liegen? Denn darauf kommt's doch an.
                            Zuletzt editiert von LXP; 19.01.2008, 23:25.

                            Comment


                            • #15
                              Originally posted by O. Helper View Post
                              Was würdest Du den in der INSERTED Tabelle bei folgendem Script erwarten? Nicht das ich die Discussion übertreiben oder Helmut Recht geben wollte ;-)

                              UPDATE Tabelle
                              SET Feld1 = Feld1
                              WHERE 1 = 2
                              Sehr einfach:
                              • Keinen Satz in DELETED
                              • Pro Satz in Tabelle einen Satz in INSERTED, mit INSERTED.Feld1 = Tabelle.Feld1, alle anderen Felder f in Tabelle mit INSERTED.f = Tabelle.f - also letztlich aufgrund des Statements eine Kopie von Tabelle

                              Unbestritten ist: Nimmt man INSERTED streng wörtlich, kann man nur das dort erwarten, was auch tatsächlich eingetragen wurde, nicht das, was eingetragen werden soll.

                              Um wieder on topic zu kommen: Mit INSERTED geht's offenbar nicht, aber der INPUTBUFFER kann natürlich helfen.

                              P.S.: Bin grad' auf ein Banner bzgl. des neuen MacBook Air gestoßen und hab' erstmal gelesen: "Das dümmste Notebook der Welt." Das war wohl nicht gemeint, schätze ich... ;-)
                              Zuletzt editiert von LXP; 19.01.2008, 22:52.

                              Comment

                              Working...
                              X