Martin Hinrichs: Rückgabewerte sind geordnet? lässt sich das verhindern?

Hallo,

ich habe ein Problem bei einer MySQL Abfrage.

Ich habe ein Request in dieser Art
SELECT name, vorname WHERE id=1002 OR id=1001 OR id=2210"

Wenn ich nun das Ergebnis checke, dann sind die IDs geordnet, also hier 1001,1002,2210. Ich brauche die IDs aber genauso in der Reihenfolge wie ich sie angegeben habe.

Was mache ich falsch?
Vielen Dank für Eure Hilfe,
Gruß, Martin

  1. Hallo,

    Was mache ich falsch?

    na ja, du machst nichts falsch, du glaubst nur was falsches. Relationale Datenbanken teile sich dadurch aus, dass eine Tabelle eine Menge von Datensätzen ist. Wie in der Mathematik so üblich hat diese Menge von Haus aus keine Ordnung. Es obliegt damit dem Datenbanksystem in welcher Reihenfolge es dir die Sätze wieder rausgibt. Dabei darfst du dich auch nicht darauf verlassen, dass diese bei zwei gleichen Abfragen auch gleich rauskommen.
    Man kann nur das Gegenteil tun: Sie explizit in eine Reihenfolge bringen mit Hilfe von ORDER BY, aber das bringt dich eher nicht weiter.

    MfG
    Rouven

    --
    -------------------
    ss:) zu:) ls:& fo:) de:< va:{ ch:? sh:) n4:( rl:? br:$ js:| ie:) fl:(
    1. Hm. Verstehe. Das ist ungünstig. Wie kann ich denn dann eine Ergebnisreihenfolge erzwingen, ohne umständliche Mehrfachrequests rauszuhauen?

      Danke Dir,
      Martin

      1. Hm. Verstehe. Das ist ungünstig. Wie kann ich denn dann eine Ergebnisreihenfolge erzwingen, ohne umständliche Mehrfachrequests rauszuhauen?

        ORDER BY. Schrieb er doch.

        1. ORDER BY. Schrieb er doch.

          Nein. ORDER BY wäre genau falsch. Ich will ja _keine_ sortierte Liste. Es ist wichtig, dass die Informationen genau so kommen, wie ich es haben will. Und da es sich um Trefferergebnisse einer Datensuche handelt, bei der die wichtigeren vorne liegen, kann ich nicht einfach eine Liste anlegen, die die Ordnung checkt.

          1. Hallo Martin

            Nein. ORDER BY wäre genau falsch. Ich will ja _keine_ sortierte Liste.

            Natürlich willst Du eine. Sonst wäre die Reihenfolge ja unwichtig und somit richtig.

            Es ist wichtig, dass die Informationen genau so kommen, wie ich es haben will.

            Ja genau danach sortiert :-)

            Und da es sich um Trefferergebnisse einer Datensuche handelt, bei der die wichtigeren vorne liegen,

            Wie ermittelst Du, was wichtiger ist? Bilde das nach.

            kann ich nicht einfach eine Liste anlegen, die die Ordnung checkt.

            Ah ja, aber die Datenbank soll wissen, was Du willst und es Dir deswegen so zurückliefern?

            UNION könnte Dir helfen. Ist aber bei z.B. mehr als drei Treffern nicht wirklich richtig schön. Ich stelle mir gerade eine Million Treffer, völlig willkürlich wichtig vor. Nein, UNION kann Dir doch nicht helfen, nur Dein Algorithmus zur Bestimmung der Wichtigkeit. Bring diesen Deiner DB bei oder sortiere in der API.

            Freundliche Grüße

            Vinzenz

          2. Hi,

            Nein. ORDER BY wäre genau falsch. Ich will ja _keine_ sortierte Liste.

            doch, genau das willst Du. Sortiert nach einem von Dir vorgegebenen Kriterium, welches dem DBMS selbstverständlich bekannt sein muss.

            Es ist wichtig, dass die Informationen genau so kommen, wie ich es haben will.

            Also sortiert.

            Und da es sich um Trefferergebnisse einer Datensuche handelt, bei der die wichtigeren vorne liegen,

            Ohne eine explizit angegebene Sortierung gibt es kein "vorne". Die Daten sind unsortiert.

            kann ich nicht einfach eine Liste anlegen, die die Ordnung checkt.

            Was immer Du hier mit "checken" meinst: Warum nicht?

            Cheatah

            --
            X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
            X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
            X-Will-Answer-Email: No
            X-Please-Search-Archive-First: Absolutely Yes
      2. Hallo Martin

        Hm. Verstehe. Das ist ungünstig. Wie kann ich denn dann eine Ergebnisreihenfolge erzwingen, ohne umständliche Mehrfachrequests rauszuhauen?

        Ich sabotiere einfach die didaktischen Ziele von Anonymous:

        Der einzige, der die Ordnungsfunktion bei _Deinen_ Daten kennt, bist _Du_. Also musst _Du_ diese dem DBMS beibringen, z.B. durch eine Zusatztabelle oder -information innerhalb Deiner Tabelle. Danach kannst Du die vorhandene Funktionalität des DBMS nutzen, d.h. mit ORDER BY sortieren.

        Sortierst Du öfter eine größere Anzahl von Datensätzen nach diesem Kriterium, so empfiehlt sich die Verwendung eines Index für die entsprechende Spalte.

        Freundliche Grüße

        Vinzenz

  2. Hello,

    Ich habe ein Request in dieser Art
    SELECT name, vorname WHERE id=1002 OR id=1001 OR id=2210"

    Wenn ich nun das Ergebnis checke, dann sind die IDs geordnet, also hier 1001,1002,2210. Ich brauche die IDs aber genauso in der Reihenfolge wie ich sie angegeben habe.

    Wozu? ;-)

    Und dann könntest Du ja immer noch

    SELECT id, name, vorname WHERE id in (1002,1001,2210);

    abfragen und das Ergebnis zur Not dann wieder im API sortieren.

    Harzliche Grüße aus http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau
  3. Hallo Martin

    Hängt Deine Frage vielleicht mit Deinem alten Thread https://forum.selfhtml.org/?t=108210&m=673427 zusammen?

    SQL bietet die Aggregatsfunktion COUNT. Nach resutierenden Spalten kannst Du selbstverständlich sortieren. Je nach DBMS könntest Du das ganze über ORDER BY, JOINS und ähnlichem erledigen. Dazu wäre eine genauere Beschreibung der Aufgabenstellung erforderlich.

    Freundliche Grüße

    Vinzenz

    1. Hallo Martin

      Hängt Deine Frage vielleicht mit Deinem alten Thread https://forum.selfhtml.org/?t=108210&m=673427 zusammen?

      Ich versuche es mal mit meiner Glaskugel:

      Du hast zwei Tabellen A und B
      A: id, name, vorname, ...
      B: id, ...

      Dein Ziel ist es, die Einträge aus A anzuzeigen (mit id, name und vorname), deren id in Tabelle B am häufigsten vorkommt. Häufigste zuerst, nur die drei häufigsten. Richtig?

      Dein Handwerkszeug ist SQL:

      SELECT
      JOIN
      COUNT
      GROUP BY, siehe SELECT
      ORDER BY
      (MySQL-spezifisch: LIMIT, siehe SELECT)

        
      SELECT  
        a.name,  
        b.vorname,  
        count(b.id) AS anzahl  
      FROM a INNER JOIN b  
      ON a.id = b.id  
      GROUP BY a.name, a.name  
      ORDER BY anzahl DESC  
      
      

      sollte liefern, was Du meiner Meinung nach suchst. Ich überlasse es Dir, die LIMIT-Klausel hinzuzufügen.

      Freundliche Grüße

      Vinzenz

      1. Hallo Vinzenz,

        vielen Dank für Deine Hilfestellung. Ja, es ist ein Folgeproblem dem der von Dir angesprochene Thread vorausgeht.

        Ich vermute, ich denke zu kompliziert und kann zusätzlich zuwenig PHP/SQL. Zu allem übel bin ich auch noch ein elender Spaghetticoder. Herrjeh. Was mach ich eigentlich vor dem Rechner. Ich wollte doch Zauberer werden. Oder Tennislehrer. Naja.

        Ich muss noch nachvollziehen, was Du geschrieben hast, aber ich kann ja noch ein paar Infos lassen.

        Das ganze ist eine Suchfunktion, die mir als eine Liste sendet mit IDs. Ursprünglich, wie im Vorthread zu lesen, war es eine Liste mit vielen Dubletten, die nun auf eine Liste mit Einzelwerten geschrumpft wurde. Inhaltlich folgt sie den Regeln:

        1.Die Werte sind so geordnet, dass die besten Ergebnisse am Anfang des Arrays stehen. Diese beinhalten die meisten "Treffer" zur Suchanfrage.
        2. Haben zwei IDs gleichviele Treffer, so sind diese so zu ordnen, dass höhere ID Nummern weiter vorne stehen.

        Nun habe ich Naivling gedacht, fein, hauste einfach eine SQL Abfrage rein, die das Array durchläuft und schon habe ich eben diese Reihenfolge auch im Ergebnis der Abfrage (d.h. ich hole mir anhand der IDs weitere Informationen).

        Naja da muss ich mir jetzt wohl was neues ausdenken. Oder?
        Vielen Dank,
        Martin

        1. Hallo Martin

          vielen Dank für Deine Hilfestellung. Ja, es ist ein Folgeproblem dem der von Dir angesprochene Thread vorausgeht.

          ist es wirklich ein Folgeproblem? Sind es nicht vielmehr zwei sich ergänzende Teilprobleme eines Gesamtproblems? Ich weiß es nicht. Schildere doch bitte das gesamte Problem.

          Ich wollte doch Zauberer werden. Oder Tennislehrer.

          *g*

          Das ganze ist eine Suchfunktion, die mir als eine Liste sendet mit IDs. Ursprünglich, wie im Vorthread zu lesen, war es eine Liste mit vielen Dubletten, die nun auf eine Liste mit Einzelwerten geschrumpft wurde.

          Wie sehen die Ausgangsdaten aus, aus der Deine Suchfunktion diese Liste generiert?
          Beispiele bitte.

          Wie sieht das gewünschte Ergebnis aus?
          Beschreibung mit Beispielen bitte.

          Freundliche Grüße

          Vinzenz

          1. Ok, ich versuche es noch genauer anhand von Beispielen.
            Stell Dir sowas wie ne Hobbysuchseite vor. Da tragen sich Leute ein und geben ihre Interessen an.
            Nun kannst Du angeben was Du suchst und bekommst die Leute angezeigt, die am meisten mit Dir gemein haben. Das ist sehr vereinfacht, reicht aber.

            Was in der Datenbank steht:
            Eine Tabelle mit persönlichen Daten der Nutzer. Nennen wir sie "personen"
            Eine Tabelle mit einer Angabe der Hobbies. Diese besteht aus einer ID, einem "Hobby" und einer ReferenzID zu den Daten in "personen". Nennen wir diese Tabelle "hobby"

            So sieht "hobby" etwa aus:

            id   hobby        personID
            --------------------------
            1    busfahren    1001
            2    schlafen     1002
            3    schlafen     1001
            4    staubsaugen  1003
            5    nachdenken   1002
            6    nachdenken   1003
            7    schlafen     1003
            [..]

            Nun kann ich als Besucher der Seite suchen, etwa nach "schlafen und  busfahren". Dabei ist nicht zwingend eine totale übereinstimmung erforderlich, sondern nur eine bestmögliche.

            mein SQL Query liefert mir dann "1001,1002,1001,1003". Nach der Umformung über array_count_values und einer Sortierung habe ich dann das schöne Ergebnis: "1001,1003,1002"
            "1001" hat die meisten Übereinstimmungen und kommt deshalb ganz vorne und 1003 kommt vor 1002 weil die ID höher ist und das heisst der Nutzer ist neuer in der Datenbank und sollte deshalb auch eher angezeigt werden.

            Naja soweit so gut, funktioniert ja alles.
            Nun würde ich nun noch die persönlichen Daten aus der DB holen wollen und diese genau in der Reihenfolge der IDs in meinem schönen Array anzeigen, aber da spielt ja wie ich jetzt gelernt habe die DB nicht mit.

            Ich werde mir jetzt ein Bier aufmachen und das Notebook beleidigen, sowas hat in der jüngeren Vergangenheit beim Denken geholfen.

            Für jeden Tipp weiterhin dankbar,
            Marting

            1. Hallo Martin       <= nicht nur ich sehe hier gerne eine Anrede

              Ok, ich versuche es noch genauer anhand von Beispielen.
              Stell Dir sowas wie ne Hobbysuchseite vor. Da tragen sich Leute ein und geben ihre Interessen an.
              Nun kannst Du angeben was Du suchst und bekommst die Leute angezeigt, die am meisten mit Dir gemein haben. Das ist sehr vereinfacht, reicht aber.

              Was in der Datenbank steht:
              Eine Tabelle mit persönlichen Daten der Nutzer. Nennen wir sie "personen"
              Eine Tabelle mit einer Angabe der Hobbies. Diese besteht aus einer ID, einem "Hobby" und einer ReferenzID zu den Daten in "personen". Nennen wir diese Tabelle "hobby"

              So sieht "hobby" etwa aus:

              id   hobby        personID

              1    busfahren    1001
              2    schlafen     1002
              3    schlafen     1001
              4    staubsaugen  1003
              5    nachdenken   1002
              6    nachdenken   1003
              7    schlafen     1003
              [..]

              Tabelle "person" oder so ähnlich sieht wohl in etwa so aus

              personID    vorname     name
              1001        Otto        Normalverbraucher
              1002        Tante       Emma
              1003        Martin      Unbekannt

              Über die mehrfachen Einträge der Hobbys (sieht grausam aus, diese neue Rechtschreibung) sag' ich mal nichts.

              Nun kann ich als Besucher der Seite suchen, etwa nach "schlafen und  busfahren". Dabei ist nicht zwingend eine totale übereinstimmung erforderlich, sondern nur eine bestmögliche.

              mein SQL Query liefert mir dann "1001,1002,1001,1003". Nach der Umformung über array_count_values und einer Sortierung habe ich dann das schöne Ergebnis: "1001,1003,1002"

              Früh, vielleicht zu früh, verläßt Du hier den SQL-Bereich

              "1001" hat die meisten Übereinstimmungen und kommt deshalb ganz vorne und 1003 kommt vor 1002 weil die ID höher ist und das heisst der Nutzer ist neuer in der Datenbank und sollte deshalb auch eher angezeigt werden.
              Naja soweit so gut, funktioniert ja alles.

              Warum hörst Du hier bereits mit SQL auf, bemühst eine externe Programmiersprache? Lass Doch SQL etwas mehr tun. Es geht.

              1. Schritt: Details reinbringen

                
              SELECT  
                 p.vorname,  
                 p.name,  
                 h.personID  
              FROM person AS p  
              INNER JOIN hobby AS h  
              ON p.personID = h.personID  
              
              

              2. Schritt: Einträge der Personen zählen

                
              SELECT  
                 p.vorname,  
                 p.name,  
                 p.personID,  
                 COUNT(h.personID) AS anzahl  
              FROM person AS p  
              INNER JOIN hobby AS h  
              ON p.personID = h.personID  
              GROUP BY p.vorname, p.name, p.personID  
              
              

              Da mit COUNT eine Aggregatsfunktion ins Spiel kommt, müssen
              alle anderen aufgeführten Spalten in die GROUP BY-Klausel
              kommen, da für diese keine Aggregatsfunktion verwendet wird.
              (Ok, MySQL ist da großzügig - ich nicht)

              3. Schritt: Halt, nur die mit den gewünschten Hobbys!
              Da nach den Hobbys nicht gruppiert wird, wird die WHERE-Klausel
              verwendet. Die WHERE-Klausel kommt im SELECT-Statement vor
              GROUP BY

                
              SELECT  
                 p.vorname,  
                 p.name,  
                 p.personID,  
                 COUNT(h.personID) AS anzahl  
              FROM person AS p  
              INNER JOIN hobby AS h  
              ON p.personID = h.personID  
              WHERE h.hobby IN ('schlafen', 'nachdenken')  
              GROUP BY p.vorname, p.name, p.personID  
              
              

              4. Schritt: Ja, aber ich will die meisten Übereinstimmungen oben
              ORDER BY mit DESC

                
              SELECT  
                 p.vorname,  
                 p.name,  
                 p.personID,  
                 COUNT(h.personID) AS anzahl  
              FROM person AS p  
              INNER JOIN hobby AS h  
              ON p.personID = h.personID  
              WHERE h.hobby IN ('schlafen', 'nachdenken')  
              GROUP BY p.vorname, p.name, p.personID  
              ORDER BY anzahl DESC  
              
              

              5. Schritt: Das reicht noch nicht, bei Gleichheit entscheidet
                 die höhere id

                
              SELECT  
                 p.vorname,  
                 p.name,  
                 p.personID,  
                 COUNT(h.personID) AS anzahl  
              FROM person AS p  
              INNER JOIN hobby AS h  
              ON p.personID = h.personID  
              WHERE h.hobby IN ('schlafen', 'nachdenken')  
              GROUP BY p.vorname, p.name, p.personID  
              ORDER BY anzahl DESC, h.personID DESC  
              
              

              Sollte das gewünschte Ergebnis liefern. Mein Code ist getestet, Fehler aus meinem vorherigen Posting sind eliminiert :-)).

              Ich weiß, dass es nicht unbedingt didaktisch klug ist, eine Komplettlösung abzuliefern, das war auch nicht meine Intention. Ich möchte Dir hier im Ansatz zeigen, was mit SQL möglich ist. Ich möchte Dich motivieren, Dich intensiver mit SQL (und auch PHP) zu befassen. Lerne, mit dem Handbuch umzugehen. Lerne, Tutorials sinnvoll zu benutzen. Das hier ist sozusagen ein Minitutorial.

              Ganz besonders möchte ich Dir zeigen, dass es sinnvoll sein kann, das Gesamtproblem zu schildern. Vielleicht kommst Du so zu einem neuen Lösungsansatz, der Dir derzeit existierende Probleme aus dem Weg räumt, weil sie dann gar nicht mehr auftreten. Ich freue mich darauf, wieder von Dir zu lesen.

              Ich werde mir jetzt ein Bier aufmachen

              Prost!

              und das Notebook beleidigen, sowas hat in der jüngeren Vergangenheit beim Denken geholfen.

              Wenn das Notebook beleidigt ist und Dir nicht mehr so recht gehorchen will, darfst Du es gern mir schenken. Ich werde es fachgerecht entsorgen.

              Freundliche Grüße

              Vinzenz

              1. Hallo Vinzenz,

                ich bin baff und bedanke mich aufrichtig für Deine ausführliche und hochinformative Antwort. Ich werde das jetzt in aller Ruhe analysieren und versuchen Deinen Ansatz für meine Zwecke zu adaptieren.

                Das wird sicher einige Zeit dauern, daher wollte ich Dir nur schonmal schnell meinen Dank aussprechen. Toll, auf so hilfsbereite Menschen zu treffen, die auch noch erklären können.

                Einen schönen Tag noch,
                Viele Grüße,
                Martin

                1. Hallo Vinzenz,

                  ich habe Dein "Tutorial" nachvollzogen und verstanden. Und noch besser: Dein Code hat auf Anhieb exakt so funktioniert wie gewünscht. Und ich hab zwanzig Zeilen absurden PHP Code wegwerfen können, der überflüssig wurde.

                  Nochmal vielen Dank für Deinen Einsatz,
                  Gruß, Martin

                  PS: neue PHP und MySQL Bücher sind auch bestellt....
                  PPS: Mit dem Notebook habe ich mich wieder vertragen. Tut mir leid.

            2. Hoi

              So sieht "hobby" etwa aus:

              id   hobby        personID

              1    busfahren    1001
              2    schlafen     1002
              3    schlafen     1001
              4    staubsaugen  1003
              5    nachdenken   1002
              6    nachdenken   1003
              7    schlafen     1003
              [..]

              Man man man, das sieht mir nach dem dicken DB fehldesign aus.
              meine version von "hobby" waere dann wohl eher so:

              id    hobby_rel     personID
              ----------------------------
              1        1           1001
              2        2           1002
              1        2           1001
              ...

              hoobbys:
              id      hobby
              ----------------------------
              1    busfahren
              2    schlafen
              ...

              So hast du irgendwann nicht 5000 mal "schlafen" in deiner DB stehen sondern immer nur INT's mit dem verweis auf das hobby.

              Aber ich bin kein Datenbank profi.

              Was sagt ihr?

              Mfg