Rückgabewerte sind geordnet? lässt sich das verhindern?
Martin Hinrichs
- datenbank
2 Rouven0 Tom0 Vinzenz Mai
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
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
Hm. Verstehe. Das ist ungünstig. Wie kann ich denn dann eine Ergebnisreihenfolge erzwingen, ohne umständliche Mehrfachrequests rauszuhauen?
Danke Dir,
Martin
Hm. Verstehe. Das ist ungünstig. Wie kann ich denn dann eine Ergebnisreihenfolge erzwingen, ohne umständliche Mehrfachrequests rauszuhauen?
ORDER BY. Schrieb er doch.
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.
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
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
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
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
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
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
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
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
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
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
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
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.
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