andreas: mysql: eine abfrage - mehrere resultsets

hallo,

ich möchte gern einen broker  bauen, der datenbankzugriffe optimiert. dafür bilde ich automatisch sql-statements der art

SELECT tab1.x, tab2.y
FROM foo AS tab1, bar AS tab2
WHERE ...

das lässt sich wunderbar generieren, leider kommt dabei immer ein resultset  raus, was nicht meinem wunsch entspricht. in dem fall käme jetzt ein set mit den spalten x und y und in den zeilen die passenden werte.

kann ich denn durch eine art 'gruppierung' des SELECT-Teils ein verschachteltes ergebnis bekommen? zu dem obigen beispiel würde ich mir nach array-wandlung sowas vorstellen:

array(
  tab1=>array(
    //result no.1 mit werten für x
  )
  tab2=>array(
    //result no.2 mit werten für y
  )

vielen dank für einen tip,
andreas

  1. Hi Andreas,
    ich kann Dir noch nicht so ganz folgen,
    worum es Dir eigentlich geht,
    aber versuch doch mal:

    SELECT tab1.x, tab2.y
    FROM foo.tab1, bar.tab2
    WHERE tab1.x = ...

    Vielleicht ist das ja was ...
    Gruss, Andy

    1. hey,

      SELECT tab1.x, tab2.y
      FROM foo.tab1, bar.tab2
      WHERE tab1.x = ...

      das ist schon so, wie ich es habe. das ergebnis sieht dann aber so aus:
      x |y
      --------
      9 |7
      9 |12
      9 |18

      was ich möchte, sieht jedoch so aus:
      x
      ----
      9

      y
      ----
      7
      12
      18

      das heisst, ich möchte die ergebismengen separat ansprechbar haben.

      grüsse,
      andreas

      1. Hi,

        das ist schon so, wie ich es habe. das ergebnis sieht dann aber so aus:
        x |y

        9 |7
        9 |12
        9 |18

        was ich möchte, sieht jedoch so aus:
        x

        9

        y

        7
        12
        18

        huestel, die uneteren Tabellen bilden die Healfte der oberen Tabelle. Beides ist so zu sagen identisch.

        das heisst, ich möchte die ergebismengen separat ansprechbar haben.

        Genau das sollte der Fall sein, wenn Du obere Tabelle mit einer serverseitigen Logik (PHP?), huestel, "zum Greifen hast". Huestel.

        Gruss,
        Ludger

        1. Genau das sollte der Fall sein, wenn Du obere Tabelle mit einer serverseitigen Logik (PHP?), huestel, "zum Greifen hast". Huestel.

          *räusper* das ist mir klar. dir ist aber nicht klar, was ich meine.

          es geht aber darum, eine universelle klasse zu schreiben, die beliebige selects annimmt, selber kombiniert und daraus _ein_ sql-statement macht. dieses wird auf funktionsaufruf zur datenbank geschickt.

          wenn ich jetzt (wie vorhin gezeigt) _ein_ resultset bekomme, ist dieses schonmal so lang, wie das längste der ergebnisse - alle spalten, die kürzer sind werden aufgefüllt, was das ergebnis natürlich mehr oder weniger unbrauchbar macht.

          selbst wenn dieses problem nicht bestünde, wäre es ein nicht zu unterschätzender aufwand, das resultat wieder auseinander zu klamüsern - insbesondere dann, wenn es grössere texte enthält. ausserdem ist nicht ausgeschlossen, dass werte vom ergebnis_1, auch im ergebnis_2 vorhanden sind. in dem fall brauche ich wahrscheinlich auch keine gesammelte sql-anfrage mehr stellen, weil die gesparte zeit für die sortierung des ergebnisses wieder darauf geht.

          es ist also notwendig, dass die 'ergebnis-tabellen'  einzeln zugreifbar sind.

          andreas

          1. Hi,

            es geht aber darum, eine universelle klasse zu schreiben, die beliebige selects annimmt, selber kombiniert und daraus _ein_ sql-statement macht. dieses wird auf funktionsaufruf zur datenbank geschickt.

            ja, gut, dann wollen wir mal von hoeherem Niveau aus die Sache betrachten, so zu sagen Sven Rautenberg maessig.

            Ein SELECT hat die Angewohnheit, datenserverseitig ausgefuehrt, eine Datensatzmenge, eine Matrix zurueckzuliefern. Jetzt moechtest Du eine Klasse schreiben, die so zu sagen schwammaehnlich SELECT-Jobs aufnimmt und daraus ein einziges SELECT Statement macht, das dann ausgefuehrt wird. Wow.

            wenn ich jetzt (wie vorhin gezeigt) _ein_ resultset bekomme, ist dieses schonmal so lang, wie das längste der ergebnisse - alle spalten, die kürzer sind werden aufgefüllt, was das ergebnis natürlich mehr oder weniger unbrauchbar macht.

            Was meinst Du denn hier genau? Du willst eine Matrix erhalten, die so zu sagen alle einzelnen Resultsets mergt? Wow.

            selbst wenn dieses problem nicht bestünde, wäre es ein nicht zu unterschätzender aufwand, das resultat wieder auseinander zu klamüsern - insbesondere dann, wenn es grössere texte enthält.

            Also das Mergen der Results wuerde ich mir noch mal ueberlegen. Ist das nicht Matrizenmultiplikation?

            ausserdem ist nicht ausgeschlossen, dass werte vom ergebnis_1, auch im ergebnis_2 vorhanden sind. in dem fall brauche ich wahrscheinlich auch keine gesammelte sql-anfrage mehr stellen, weil die gesparte zeit für die sortierung des ergebnisses wieder darauf geht.

            Huestl, was ist denn

            ergebnis1                  UND
             ergebnis2

            ?

            es ist also notwendig, dass die 'ergebnis-tabellen'  einzeln zugreifbar sind.

            Eine Funktion, die ein Matrizen-Array zurueckgibt. Hmm.

            Also, viel Glueck und so.

            Gruss,
            Ludger

            1. Hi,
              Was meinst Du denn hier genau? Du willst eine Matrix erhalten, die so zu sagen alle einzelnen Resultsets mergt? Wow.

              ich glaube, das ist was ich meine. also eben die matrizen nicht schichtenmässig übereinander zurück, sondern aneinandergekettet - untereinander (wenn ich mir das gerade richtig vorstelle).

              grüsse,
              andreas

          2. Hallo,

            es geht aber darum, eine universelle klasse zu schreiben, die beliebige selects annimmt, selber kombiniert und daraus _ein_ sql-statement macht. dieses wird auf funktionsaufruf zur datenbank geschickt.
            es ist also notwendig, dass die 'ergebnis-tabellen'  einzeln zugreifbar sind.

            Bist Du sicher, dass so etwas überhaupt möglich ist? Nach meiner bescheidenen Meinung bringt _ein_ SELECT-Statement genau _ein_ Resultset. Selbst wenn Du mehrere Statements mit ;-Trenner innerhalb eines Datenbank-Zugriffs absetzen kannst, wüsste ich nicht, wie Du mehrere Resultsets davon zurückerhalten könntest.

            viele Grüße

            Axel

            1. Hallo,

              Bist Du sicher, dass so etwas überhaupt möglich ist? Nach meiner bescheidenen Meinung bringt _ein_ SELECT-Statement genau _ein_ Resultset. Selbst wenn Du mehrere Statements mit ;-Trenner innerhalb eines Datenbank-Zugriffs absetzen kannst, wüsste ich nicht, wie Du mehrere Resultsets davon zurückerhalten könntest.

              naja, das ist gerade der grund des postings ;)
              ich dachte, vielleicht wollte das schonmal jemand vor mir haben.  ich brauche ja auch nicht zwingend 'separate resultsets', nur eben mit dem 'kartesischen produkt' (neu gelernt), kann ich in dem fall nichts anfangen.

              grüsse,
              andreas

          3. es ist also notwendig, dass die 'ergebnis-tabellen'  einzeln zugreifbar sind.

            Wenn du die Daten nicht verknüpfen willst, dann verknüpfe sie doch einfach nicht und greife einzeln darauf zu: Wo ist da denn dein Problem? Dass du dir eine Datenbank-Abfrage sparen willst?

            Das was bei dir rauskommt nennt sich übrigens Kartesisches Produkt. Deine beiden Ergebnismengen werden miteinander multipliziert. Beispielsweise ergeben zwei gefundene Datensätze aus A und drei gefundene Datensätze aus B insgesamt 6 Ergebniszeilen. Das solltest du nur tun, wenn du das wirklich so haben willst.

            1. Wenn du die Daten nicht verknüpfen willst, dann verknüpfe sie doch einfach nicht und greife einzeln darauf zu: Wo ist da denn dein Problem? Dass du dir eine Datenbank-Abfrage sparen willst?

              genau. bloss dass es eben manchmal mehr als nur eine abfrage ist, die man sparen könnte. vorrausgesetzt das funktioniert.

              Das was bei dir rauskommt nennt sich übrigens Kartesisches Produkt. Deine beiden Ergebnismengen werden miteinander multipliziert. Beispielsweise ergeben zwei gefundene Datensätze aus A und drei gefundene Datensätze aus B insgesamt 6 Ergebniszeilen. Das solltest du nur tun, wenn du das wirklich so haben willst.

              hmm, danke :) aber genau das will ich ja eben nicht...

              grüsse,
              andreas

          4. Moin!

            es geht aber darum, eine universelle klasse zu schreiben, die beliebige selects annimmt, selber kombiniert und daraus _ein_ sql-statement macht. dieses wird auf funktionsaufruf zur datenbank geschickt.

            Ich denke, dieser Wunsch wird sich nicht erfüllen lassen.

            Das Ergebnis einer Datenbankabfrage ist immer _eine_ Tabelle mit sovielen Spalten, wie im SELECT angegeben, und sovielen Zeilen, wie Ergebnisse auf die WHERE-Bedingung (in Kombination mit evtl. GROUP BY) passen.

            Wenn du jetzt beliebige SELECTs annehmen willst, um daraus EIN SELECT zu machen, warum machst du als Mensch nicht aus diesen beliebigen SELECTs gleich direkt eines? Würde es einen Mechanismus geben, der beliebige SELECTs zu einem zusammenfaßt, könnte man ja mit einer einzigen Datenbankabfrage sozusagen alles machen, was man jemals wollte - sozusagen das gesamte Wissen der Menschheit mit einem einzigen SELECT abfragen.

            Und was universelle Klassen angeht: Die halte ich dann für reichlich sinnlos, wenn sie lediglich die bekannten Abfragefunktionen der Datenbank kapseln. mysql_query() in eine Klasse zu verpacken ist ziemlich sinnlos - da sollte die Klasse schon wesentlich mehr zu leisten imstande sein. Wenn sie aber mehr leistet, dann ist sie nicht mehr so universell. Ich bin sehr dafür, nicht in allen Lebenslagen immer universell benutzbaren Code zu schreiben - das macht die Aufgabe nämlich meist unnötig komplex, weil auch Fälle zu beachten sind, die für die aktuelle Anwendung gar nicht nötig wären - sondern lieber exakt auf das Problem angepaßten Code. Das produziert in der Regel weniger Codezeilen, die Ausführung ist dadurch schneller, und auch die Programmierung geht fixer.

            es ist also notwendig, dass die 'ergebnis-tabellen'  einzeln zugreifbar sind.

            Du wirst zwingend einzelne SELECTs an die DB schicken müssen und erhälst im Gegenzug wunderbar einzelne Resultsets.

            - Sven Rautenberg

            1. heyho,
              [...]

              Ich denke, dieser Wunsch wird sich nicht erfüllen lassen.

              danke für deine ausführliche antwort. was mich aber jetzt schon interessiert: geht das denn  generell nicht? habe ich die verwendung eines 'brokers' missverstanden? datenbankabfragen müssen sich doch irgendwie optimieren lassen (ausserhalb der db)...?

              Und was universelle Klassen angeht: Die halte ich dann für reichlich sinnlos, wenn sie lediglich die bekannten Abfragefunktionen der Datenbank kapseln. mysql_query() in eine Klasse zu verpacken ist ziemlich sinnlos - da sollte die Klasse schon wesentlich mehr zu leisten imstande sein.

              das sehe ich anders; eine db-abstraktionsschicht (à la PEAR:DB) allein ist ja schon grund genug zur kapselung. aber auch ohne die, hätte ich keinen bock, jedes mißglückte sql-statement irgendwo zu suchen und möglicherweise mehrfach hin- und her zu kopieren. viele db-abfragen sind so einfach aufgebaut, dass man mit einer schönen funktion komfortabler dran ist. diese kann ja intern trotzdem noch prüfen, ob statt der erwarteten parameter (zb. $table, $fields_array, $condition_array) ein einzelner sql-string übergeben wurde - bei ja, macht sie auch den. schwuppdiwupp, datenbank entkoppelt :)

              viele grüsse,
              andreas

              1. Hi,

                Ich denke, dieser Wunsch wird sich nicht erfüllen lassen.

                danke für deine ausführliche antwort. was mich aber jetzt schon interessiert: geht das denn  generell nicht? habe ich die verwendung eines 'brokers' missverstanden? datenbankabfragen müssen sich doch irgendwie optimieren lassen (ausserhalb der db)...?

                Du hast das Wesen von Daten nicht verstanden. Daten sind codierte Informationen aus der realen Welt, deren Struktur ebenfalls nicht frei waehlbar sind, sondern vorgegeben. Aus diesem einfachen Grund kannst Du Resultsets von Datenbankabfragen nicht tabellarisch zusammenfuehren.
                Aber, was Du grundsaetzlich ins Auge fassen koenntest ist eine XML-basierte Zusammenfuehrung verschiedener Resultsets, so zu sagen objektorientierte Datenhaltung.

                Gruss,
                Ludger

              2. Moin!

                Ich denke, dieser Wunsch wird sich nicht erfüllen lassen.

                danke für deine ausführliche antwort. was mich aber jetzt schon interessiert: geht das denn  generell nicht?

                Nein.

                Du kannst die Lottozahlen vom letzten Samstag, die Noten deines letzten Zeugnisses und die Anzahl der Löchern in deinen Strüpfen abfragen. Das Ergebnis wird in jedem Einzelfall ein Integer im Bereich 0 bis 49 sein (hoffe ich mal, ich kenne deine Strüpfe natürlich nicht) und sich deswegen mit UNION SELECT auch in EINE Abfrage zwängen lassen - aber mal im Ernst: Hast du in der Literatur (auf gedrucktem Papier) schon mal so eine beknackte Tabelle gesehen in der untereinander Lottozahlen, Noten und Löcherzahlen drinstanden - drei voneinander vollkommen unabhängige Informationen, die nichts miteinander zu tun haben?

                Datenbanken haben aber nur mit Daten zu tun, die etwas miteinander zu tun haben. Deswegen kann man in einer einzelnen Abfrage auch nur eine Tabelle erhalten, die alle abgefragten Daten, die etwas miteinander zu tun haben, auflistet.

                habe ich die verwendung eines 'brokers' missverstanden? datenbankabfragen müssen sich doch irgendwie optimieren lassen (ausserhalb der db)...?

                Wenn man die Abfragen optimieren kann, dann kann man das auch manuell machen - was unter Umständen zeitaufwendiger ist, weil der Mensch eben nicht so schnell rechnen kann, wie ein Computer, aber vom Ergebnis her absolut identisch sein müßte.

                Da man aber nicht beliebige, voneinander unabhängige Tabellenabfragen zusammenfassen kann - es scheitert ja schon dann, wenn die einzelnen Abfragen unterschiedliche Anzahlen von Spalten haben - kann auch kein Programm diese Abfragen zusammenfassen.

                Die Datenbank selbst optimiert die eingegangenen Abfragen ja auch. Aber nicht, indem sie zusammengefaßt werden (weil das eine Abfrage unnötig komplexer und damit zeitaufwendiger machen würde), sondern indem sie z.B. WHERE-Bedingungen umformt.

                Es dürfte in der Tat für eine Datenbank einfacher sein, nacheinander drei voneinander unabhängige Abfragen in drei verschiedenen Tabellen (oder gar Datenbanken) zu beantworten, als mit Krawall diese drei Antworten zusammenzumischen. Das Zusammenmischen dauert mindestens so lange, wie die drei Abfragen zusammenaddiert, aber da die Ausführung der Multiabfrage (wenn sie denn tatsächlich möglich ist) als ein Block ausgeführt werden muß, müssen weitere Anfragen von anderen Prozessen z.B. bis zum Ende dieses ganzen Blocks warten und können nicht mal eben dazwischengeschoben werden.

                - Sven Rautenberg

  2. yo,

    kann ich denn durch eine art 'gruppierung' des SELECT-Teils ein verschachteltes ergebnis bekommen? zu dem obigen beispiel würde ich mir nach array-wandlung sowas vorstellen:

    wenn ich das richtig verstanden habe, dann sollte dir UNION weiterhelfen, wobei ich nicht sicher bin, ob mysql das beherscht und wenn ja, ab welcher version.

    Ilja

    1. hallo,

      wenn ich das richtig verstanden habe, dann sollte dir UNION weiterhelfen, wobei ich nicht sicher bin, ob mysql das beherscht und wenn ja, ab welcher version.

      leider geht das nicht.
      das ergebnis ist auf die gleiche spaltenzahl begrenzt und wird innerhalb der spalte nacheinander aufgelistet.

      grüsse,
      andreas

      1. yo,

        das ergebnis ist auf die gleiche spaltenzahl begrenzt und wird innerhalb der spalte nacheinander aufgelistet.

        die gleiche spaltenanzahl läßt sich umgehen, indem man die maximale spaltenanzahl ermittelt und bei den restlichen abfragen mit "dummys" füllt. den zweiten teil des satzes nach dem und verstehe ich nicht genau, was du damit meinst.

        Ilja

        1. yo,
          die gleiche spaltenanzahl läßt sich umgehen, indem man die maximale spaltenanzahl ermittelt und bei den restlichen abfragen mit "dummys" füllt. den zweiten teil des satzes nach dem und verstehe ich nicht genau, was du damit meinst.

          bei dieser abfrage z.b.
          SELECT introduction FROM tbl_article_main
          UNION
          SELECT article_name FROM tbl_article
          ;

          wird das ergebnis beider abfragen in einer spalte 'introduction' nacheinander aufgelistet. leider ist kein trenner dazwischen, so dass ich das wieder auseinander bekomme.

          andreas

          1. yo,

            leider ist kein trenner dazwischen, so dass ich das wieder auseinander bekomme.

            der trenner ist einfach, wieder eine "künstliche" spalte anlegen, zum beispiel erste abfrage mit dem wert 1, zweite abfrage mit dem wert 2....

            Ilja

            1. hey,

              der trenner ist einfach, wieder eine "künstliche" spalte anlegen, zum beispiel erste abfrage mit dem wert 1, zweite abfrage mit dem wert 2....

              ok, dann danke ich dir :)
              sieht so aus, dass es irgendwie gehen muss, ob sichs lohnt muss ich erst probieren.

              vielen dank und beste grüsse,
              andreas

              1. yo,

                sieht so aus, dass es irgendwie gehen muss, ob sichs lohnt muss ich erst probieren.

                zum einen musst du sehen, ob es unter deiner mysql version überhaupt ein UNION gibt. und selbst wenn, würde ich deine idee verwerfen. UNION kommt im gegensatz zu dem karthesischen produkt deiner idee zwar näher. aber es lohnt sich nicht immer alles in eine abfrage packen zu wollen. oftmals sind mehrere abfragen einfach besser. sicherlich kannst du es versuchen. ich würde mir aber die zeit sparen.

                Ilja