Lothar: SQL Frage zu update

Guten Tag,

ich möchte einen Tabellenupdate schreiben, der mir Probleme macht. Ich habe diese 4 Tabellen.

Tabelle a:
aID(int), Lob(dec)

Tabelle f:
fID, Lob(dec)

Tabelle t:
tID, Lob(dec)

Tabelle b:
Part(char),ID(int),Lob(dec)

Alle Einträge der 3 Tabellen a,f,t befinden sich in Tabelle b wieder, d.h. sie müssen dort redundant gespeichert werden. Hierbei beinhaltet die Spalte "Part" den Tabellennamen, also a,f oder t. Und die Spalte "ID" beinhaltet die jeweilige ID des Tabelleneintrages, somit ist der jeder Eintrag in Tabelle b eindeutig einem Eintrag der Tabellen a,f oder t entsprechend.

Nun möchte ich Tabelle b updaten und zwar möchte ich die Spalte "Lob" aus den Tabellen a,f,t auf die Tabelle b "eintragsgetreu" übertragen.

Ich denke, dass ich das schaffe, aber ich bin nicht sicher, ob ich das auf die effektivste Weise schaffe.

Könnt Ihr mir mal einen Tip geben, wie der effektivste Weg ist?

Schönen Sonntag, Lothar

  1. Tach!

    Alle Einträge der 3 Tabellen a,f,t befinden sich in Tabelle b wieder, d.h. sie müssen dort redundant gespeichert werden.

    Ich würde mir überlegen, ob ich da nicht eine View schreiben kann statt einer Tabelle. Die View kann die Daten aus den anderen Tabellen abfragen und mit UNION zusammenführen.

    dedlfix.

    1. Hallo,

      Ich würde mir überlegen, ob ich da nicht eine View schreiben kann statt einer Tabelle. Die View kann die Daten aus den anderen Tabellen abfragen und mit UNION zusammenführen.

      Mit views kenne mich mich nicht aus. Gibt es nichts in der Art

      UPDATE b SET Lob = SELECT Lob FROM ... CASE oder IF... ??

      Ansonsten wäre ich gerne bereit, views zu lernen. Kannst Du mir das grob erklären?

      Lothar

      1. Tach!

        Mit views kenne mich mich nicht aus.

        Eine View ist eine vorgefertigte Query, die komplex sein kann, aber sich als View so einfach wie eine Tabelle verwenden lässt, mit demselben SELECT-Statement wie für eine Tabelle.

        Gibt es nichts in der Art

        UPDATE b SET Lob = SELECT Lob FROM ... CASE oder IF... ??

        Wenn die Tabelle b immer genau die Inhalte der anderen drei enthalten soll ohne zusätzliche oder fehlende Eintrage, würde ich nicht mit UPDATE hantieren wollen, sondern mit TRUNCATE und INSERT ... SELECT .... Wenn es denn eine physische Tabelle sein soll. Das UPDATE behandelt ja nur die vorhandenen Datensätze und keine in a,f,t neu hinzugekommenen. INSERT ... ON DUPLICATE KEY UPDATE wäre auch noch eine Variante.

        Das SELECT-Statement wiederum wäre auch gleich die Grundlage für die View.

        SELECT 'a' part, aId ID, Lob FROM a
        UNION
        SELECT 'f' part, fId ID, Lob FROM f
        UNION
        SELECT 't' part, tId ID, Lob FROM t
        

        Wenn du unbedingt die physische Tabelle und das UPDATE brauchst, dann kannst du ebenfalls dieses SELECT nehmen, es als Subquery in das UPDATE-Statement joinen und über WHERE die passenden Datensätze zueinander finden.

        Ansonsten wäre ich gerne bereit, views zu lernen. Kannst Du mir das grob erklären?

        Die konkrete Syntax hab ich nicht im Kopf, aber die gibts im MySQL-Handbuch.

        dedlfix.

        1. Wusste gar nicht, dass das "AS" für einen Column-Alias optional ist...

          Das entscheidende Kriterium für View oder nicht ist der Anwendungszweck. Hast Du B nur eingeführt, um die A, F und T Tabellen übergreifend abfragen zu können? Oder gibt's noch andere Gründe?

          Rolf

          1. Das entscheidende Kriterium für View oder nicht ist der Anwendungszweck. Hast Du B nur eingeführt, um die A, F und T Tabellen übergreifend abfragen zu können? Oder gibt's noch andere Gründe?

            Nein, nein…

            Tabelle b umfasst noch viel mehr Informationen und noch wichtiger, in den Tabellen a,f und t dürfen sich später noch Dinge ändern, die in b nicht mehr geändert werden dürfen.

            1. Tach!

              Tabelle b umfasst noch viel mehr Informationen und noch wichtiger, in den Tabellen a,f und t dürfen sich später noch Dinge ändern, die in b nicht mehr geändert werden dürfen.

              Das präzisiert die Aufgabenstellung und damit ist eine View nicht mehr verwendbar, weil die ja nur eine andere Sicht auf den jeweiligen Datenbestand von a,f,t ist. Bleibt die Variante mit dem UPDATE und dem gejointen SELECT-UNION-Konstrukt.

              dedlfix.

            2. Ooookay. Geht es nur um ein UPDATE, oder musst Du auch hinzugekommene Sätze nachtragen?

              Konstrukte wie IF oder CASE gelten nicht für die Table; wenn es nur um UPDATE geht, würde ich 3 UPDATE Statements laufen lassen.

              UPDATE b SET Lob = (SELECT Lob FROM a WHERE aID = ID) WHERE Part = 'a'
              UPDATE b SET Lob = (SELECT Lob FROM f WHERE fID = ID) WHERE Part = 'f'
              UPDATE b SET Lob = (SELECT Lob FROM t WHERE tID = ID) WHERE Part = 't'
              

              Rolf

              1. Ooookay. Geht es nur um ein UPDATE, oder musst Du auch hinzugekommene Sätze nachtragen?

                Nein, es geht definitiv ausschließlich um ein Update vorhandener Datensätze.

                Konstrukte wie IF oder CASE gelten nicht für die Table; wenn es nur um UPDATE geht, würde ich 3 UPDATE Statements laufen lassen.

                UPDATE b SET Lob = (SELECT Lob FROM a WHERE aID = ID) WHERE Part = 'a'
                UPDATE b SET Lob = (SELECT Lob FROM f WHERE fID = ID) WHERE Part = 'f'
                UPDATE b SET Lob = (SELECT Lob FROM t WHERE tID = ID) WHERE Part = 't'
                

                Habe ich noch gar nicht drüber nachgedacht, dass ich ja auch mehrere Queries machen kann.

                Dennoch würde ich gerne auch dedlfixs' gejointen SELECT-UNION-Konstrukt-Update Lösung verstehen.

                1. Dedlfixens Konstrukt enthält mehrere Dinge, die Du möglicherweise nicht kennst.

                  (1) UNION. Das ist ein SQL Sprachkonstrukt, das die Ergebnismengen mehrerer SELECTs zu einer Ergebnismenge zusammenfasst. Funktioniert natürlich nur, wenn die SELECTS so sind, dass das machbar ist (gleiche Spaltenzahl, gleiche oder zumindest konvertierbare Datentypen). Gleiche SpaltenNAMEN müssen es übrigens nicht unbedingt sein, SQL verwendet bei Widersprüchen die Namen des ersten SELECT (gilt für MS SQL Server, ob das auch bei MySQL so ist, weiß ich nicht).

                  UNION macht noch etwas mehr als nur Zeilen aneinander zu kängen. Er bildet eine echte Vereinigungsmenge, d.h. er entfernt Duplikate, was bei großen Datenmengen durchaus Zeit kosten kann. Will man diesen Schritt vermeiden, schreibt man statt "UNION" ein "UNION ALL".

                  (2) Konstanten in der SELECT Liste. Dafür gibt es unterschiedliche Anlässe. Einer ist, wenn man ein UNION-Konstrukt hat und den Ergebnissätzen ihre Herkunft ansehen können will. Das passiert hier.

                  (3) Alias-Namen für Ergebnisspalten. Verwendet man, um bei Angabe von Konstanten für eine Spalte einen definierten Spaltennamen zu haben, oder um Spalten für die Ergebnismenge umzubenennen. Normalerweise wird ein Alias mit AS definiert, also aID as ID, das AS ist aber optional.

                  Du kannst dein Update nun so schreiben, ganz ausführlich:

                  UPDATE b
                  SET Lob = (SELECT Lob
                             FROM (SELECT 'a' part, aId ID, Lob FROM a
                                   UNION
                                   SELECT 'f' part, fId ID, Lob FROM f
                                   UNION
                                   SELECT 't' part, tId ID, Lob FROM t) aft
                             WHERE aft.part = b.part AND aft.ID = b.ID)
                  

                  D.h. du klebst die drei Teil-Queries erstmal zusammen, um dann per WHERE einen einzigen Satz davon herauszufieseln. Das ist eine Herausforderung für den Optimizer im SQL Server, darum habe ich dieses Statement rot angepinselt.

                  Man kann VIEWs aber auch als Datenbankobjekte erzeugen - hier in der einfachsten Form. Die ekligen Details findest Du hier.

                  CREATE VIEW aft AS
                     SELECT 'a' part, aId ID, Lob FROM a
                     UNION
                     SELECT 'f' part, fId ID, Lob FROM f
                     UNION
                     SELECT 't' part, tId ID, Lob FROM t
                  

                  Mit diesem View wird das Updatemonster von oben zu

                  UPDATE b
                  SET Lob = (SELECT Lob FROM aft WHERE aft.part = b.part AND aft.ID = b.ID)
                  

                  Sieht trügerische simpel aus, ist aber für den SQL Optimizer genauso problematisch wie das Monster. Die Ergebnismenge eines VIEW wird nicht gespeichert. Du kannst den VIEW hier wie einen Textbaustein betrachten, der in eine Query eingefügt wird. Ok ok, das war eine "Lüge für Kinder" - hinter Views steckt mehr als das...

                  D.h. als "grün", oder empfehlenswert, würde ich für deine Aufgabenstellung die Lösung mit den 3 Updates ansehen.

                  Rolf

                  1. Hallo Rolf,

                    boah, danke für die lange, gute Erklärung!!! Ich habe sie aber erst einmal gelesen. Ich muß sie aber öfter lesen, um sie wirklich zu verstehen.

                    Union und Aliasse kannte ich schon. Und ich wußte auch, dass man sie in mysql ohne AS notieren kann, aber ich habe hier tatsächlich übersehen, dass es sich um ein Alias handelt. Liegt auch daran, dass die Konstante (die kannte ich übr. nicht) seltsamerweise nicht mit einem Komma abgetrennt wird?

                    So, jetzt muß ich mir Dein Post noch 3-4 mal durchlesen, dann hab ichs bestimmt. 😉

                    Danke an Dich (und dedlfix).

                    1. Da hast Du schief geguckt. Die konstante Spalte WIRD mit einem Komma abgetrennt.

                         SELECT 'a' part, aID ID, Lob FROM a...
                      oder
                         SELECT 'a' AS part, aID AS ID, Lob FROM a...
                      

                      erzeugt 3 Spalten.

                      • Spalte 1: Name ist 'part', Wert ist konstant 'a'
                      • Spalte 2: Name ist 'ID', Wert ist der Wert der aID Spalte
                      • Spalte 3: Name ist 'Lob', Wert ist der Wert der Lob Spalte

                      Rolf

                      1. Da hast Du schief geguckt. Die konstante Spalte WIRD mit einem Komma abgetrennt.

                           SELECT 'a' part, aID ID, Lob FROM a...
                        oder
                           SELECT 'a' AS part, aID AS ID, Lob FROM a...
                        

                        erzeugt 3 Spalten.

                        • Spalte 1: Name ist 'part', Wert ist konstant 'a'
                        • Spalte 2: Name ist 'ID', Wert ist der Wert der aID Spalte
                        • Spalte 3: Name ist 'Lob', Wert ist der Wert der Lob Spalte

                        Hi Rolf,

                        danke nochmal für die Erklärung. Spalte 1 hatte ich nicht kapiert.

                        Letztlich habe ich alles umgesetzt, es auch fast verstanden (ist wirklich ein kompliziertes Konstrukt), aber es hat dennoch nicht funktioniert. mysql hat gemeckert, dass da verschiedene Zeichensätze am Werk sind und deshalb habe ich kein Ergebnis erhalten.

                        Dennoch habe ich wieder etwas gelernt. Nur für mein Vorhaben mußte ich dann doch auf Deine 3 Abfragen zurückgreifen. Das läuft dann auch sauber, ich habs getestet.

                        Thanx nochmal!

        2. Hallo,

          Das SELECT-Statement wiederum wäre auch gleich die Grundlage für die View.

          SELECT 'a' part, aId ID, Lob FROM a
          UNION
          SELECT 'f' part, fId ID, Lob FROM f
          UNION
          SELECT 't' part, tId ID, Lob FROM t
          

          Kannst Du mir diese Query erklären? Ich verstehe sie leider nicht.

          Wenn du unbedingt die physische Tabelle und das UPDATE brauchst, dann kannst du ebenfalls dieses SELECT nehmen, es als Subquery in das UPDATE-Statement joinen und über WHERE die passenden Datensätze zueinander finden.

          Und das erst recht nicht. :-(

          Ansonsten wäre ich gerne bereit, views zu lernen. Kannst Du mir das grob erklären?

          Die konkrete Syntax hab ich nicht im Kopf, aber die gibts im MySQL-Handbuch.

          Ich habe jetzt schon eion paar Seiten über views gelesen, aber ich denke, Du wolltest damit meine b-Tabelle ersetzen. Die brauche ich aber unbedingt.