MySQL order by + rand()
fritz85
- datenbank
Hallo zusammen
ich hätte da eine Frage.
Ich lese viele Einträge aus der DB. Wichtig ist das die, die premium = 1 sind zu vorderst sind.
Nun möchte ich alle premium im Random verfahren anzeigen und die restlichen normal nach s.time DESC sortieren.
Gibt es da eine Lösung oder ist dies unmöglich?
Hier mein jetziger Query:
$query = $db->dbquery("SELECT
s.*,
k.name AS
knameFROM
eintraegeAS
sLEFT JOIN
regionAS
k ON k.id = s.kanton WHERE s.status = '1' ORDER BY s.premium DESC, s.time DESC LIMIT $start,$ins_page");
Danke und Gruss
fritz85
Hi!
Ich lese viele Einträge aus der DB. Wichtig ist das die, die premium = 1 sind zu vorderst sind.
Nun möchte ich alle premium im Random verfahren anzeigen und die restlichen normal nach s.time DESC sortieren.
Du möchtest also zwei Ergebnismengen vereinen. Die erste beinhaltet die nach Zufall sortierten Premium-Daten, die zweite die nach Zeit sortierten Nicht-Premium-Daten. Ergibt zwei SELECTs vereint mit UNION.
Lo!
Hallo Lo!
Du möchtest also zwei Ergebnismengen vereinen. Die erste beinhaltet die nach Zufall sortierten Premium-Daten, die zweite die nach Zeit sortierten Nicht-Premium-Daten. Ergibt zwei SELECTs vereint mit UNION.
genau du hast das richtig erfasst - ich studiere gerade das UNION.. *amkopfkratz*
Hallo
bin jetzt gerade dran.. jedoch seh ich denn Fehler nix. Denn meine Abfrage macht genau das gleiche wie vorhin.
$query = $db->dbquery("
(SELECT `s`.*, `k`.name AS `kname` FROM `eintraege` AS `s` LEFT JOIN `region` AS `k` ON k.id = s.kanton WHERE s.name != '' AND s.cat LIKE '".$catdb."' AND s.status = '1' ORDER BY s.premium DESC, s.time DESC LIMIT $start,$ins_page)
UNION
(SELECT `s`.*, `k`.name AS `kname` FROM `eintraege` AS `s` LEFT JOIN `region` AS `k` ON k.id = s.kanton WHERE s.name != '' AND s.cat LIKE '".$catdb."' AND s.status = '1' AND s.premium = '1' ORDER BY RAND() LIMIT $start,$ins_page)");
Hi!
bin jetzt gerade dran.. jedoch seh ich denn Fehler nix. Denn meine Abfrage macht genau das gleiche wie vorhin.
Der PHP-Code ist an dieser Stelle uninteressant. Viel besser wäre es gewesen, wenn du das Statement lesbarer formatiert hättest. Dann wäre dir vielleicht auch aufgefallen, dass du zwar einmal die Premium-Daten selektierst, beim anderen sie aber nicht ausschließt. Ich hatte deine Aufgabenstellung umformuliert, um dir zu zeigen, wie die Abfrage aussehen muss (und nicht um zu zeigen, dass ich es verstanden hatte). Außerdem wolltest du zuerst die Premium-Sätze und dann erst die anderen, also musst du zuerst die Premium-Abfrage notieren und anschließend die Nicht-Premium-Abfrage. Sortieren nach Premium musst du nicht mehr, denn die Ergebnismengen werden durch das UNION nicht vermischt (solange du kein gemeinsames ORDER BY notierst).
(SELECT ...
FROM `eintraege` AS `s`
LEFT JOIN ...
WHERE
... AND
s.premium = '1' -- hier ist's
ORDER BY RAND()
LIMIT ...)
UNION
(SELECT ...
FROM `eintraege` AS `s`
LEFT JOIN ...
WHERE
... AND
s.premium <> '1' -- hier fehlt's
ORDER BY
s.premium DESC, -- muss weg
s.time DESC
LIMIT ...)
Diese Formatierung kannst du auch so in deinem PHP-Code notieren, dann kann man es auch da leichter lesen.
Lo!
Hello Lo!
wunderbar das Randomverfahren funktioniert bei den Premium-Einträgen. (VIELEN DANK!) Jedoch funktioniert nun das LIMIT nicht mehr welches mit dem Paging zusammen verbunden ist.
ich habe:
LIMIT 0, 10
Mal fix reingeschrieben.
Jetzt zeigt er mir 10 Premium Einträge (soviel hat es auch freigeschaltet) und 10 Nicht-Premium-Einträge.
Auf der zweiten Seite stimmen die Anzahl Einträge (10 Einträge) wieder.
Gruss
fritz85
Hi!
Jedoch funktioniert nun das LIMIT nicht mehr welches mit dem Paging zusammen verbunden ist.
Ja, stimmt, das LIMIT muss auch außen hin und nicht in die Teilabfragen.
Lo!
Hello
Ja, stimmt, das LIMIT muss auch außen hin und nicht in die Teilabfragen.
Das hab ich gemacht :)
(SELECT ...
FROM `eintraege` AS `s`
LEFT JOIN ...
WHERE
... AND
s.premium = '1'
ORDER BY RAND()
LIMIT 0, 10)
UNION
(SELECT ...
FROM `eintraege` AS `s`
LEFT JOIN ...
WHERE
... AND
s.premium <> '1'
ORDER BY
s.premium DESC,
s.time DESC
) LIMIT 0, 10
So funktioniert es auch jedoch werden die Nicht-Premium-Einträge nicht nach s.time DESC sortiert. :-/
Hi!
Ja, stimmt, das LIMIT muss auch außen hin und nicht in die Teilabfragen.
Das hab ich gemacht :)
Ja, eins. Und das obere muss auch noch raus, oder willst du von den Premiums generell nur 10 angezeigt bekommen?
WHERE
... AND
s.premium <> '1'
ORDER BY
s.premium DESC,
s.time DESCSo funktioniert es auch jedoch werden die Nicht-Premium-Einträge nicht nach s.time DESC sortiert. :-/
Wenn der Wert in s.premium nur 0 oder 1 annehmen kann, und die 1 ausgeschlossen ist, muss auch nicht nach dem Rest sortiert werden. Da in deinem Fall der Rest aber nur (anzunehmenderweise) 0 ist, sollte er keine Auswirkungen auf die Reihenfolge haben, weil dann immer das zweite Sortierkriterium (s.time) zieht. Es sollte also nur so lauten:
ORDER BY
s.time DESC
Warum es dann aber nicht sortieren soll, entzieht sich meiner Kenntnis. Der Feldtyp in s.time ist ein Datumstyp oder ein Integer, der einen Unix-Timestamp verkörpert, oder ein String?
Wenn du mal die zweite Teilabfrage einzeln mit phpMyAdmin oder ähnlichem Tool ausführst, wird es dann richtig sortiert ausgegeben?
Lo!
Guten Morgen Lo!
Ja, eins. Und das obere muss auch noch raus, oder willst du von den Premiums generell nur 10 angezeigt bekommen?
Nein das natürlich nicht es kann ja immer mehr geben, ausserdem wird $start, $ins_page durch zwei Parameter gesteuert, anyway.
ORDER BY
s.time DESC
Sorry, das hatte ich bereits so drin.
Warum es dann aber nicht sortieren soll, entzieht sich meiner Kenntnis. Der Feldtyp in s.time ist ein Datumstyp oder ein Integer, der einen Unix-Timestamp verkörpert, oder ein String?
ist ein Unix Timestamp.
Ich hab es nun so gemacht beim 1 Statement das LIMIT weggenommen (=> RAND funktioniert nicht mehr)
Die Sortierung bei den Nicht-Premium-Einträge ist noch immer falsch.
Gruss
fritz85
Hi!
Die Sortierung bei den Nicht-Premium-Einträge ist noch immer falsch.
Wenn alles Probieren nicht hilft, muss man vielleicht doch mal ins Handbuch schauen. Und das sagt zu UNION und der Sortiererei im unteren Teil, dass die Ergebnisse beider Statements per Definition in unsortierter Reihenfolge aus dem UNION rauskommen. Das ist also die Ursache. Doch wie ist die Lösung? Das Handbuch sagt: Das Nicht-Vermischen der Teilergebnisse erreicht man, indem man eine Sortierspalte einfügt, nach der man dann global sortieren kann
(SELECT 1 AS sort1, ... WHERE premium)
UNION
(SELECT 2 AS sort1, ... WHERE nicht_premium)
ORDER BY sort1
Und die Teilergebnisse selbst? Da soll man eine zweite Sortierspalte einfügen. Und da muss man in deinem Fall das RAND() berücksichtigen.
(SELECT 1 AS sort1, RAND() AS sort2, ... WHERE premium)
UNION
(SELECT 2 AS sort1, s.time AS sort2, ... WHERE nicht_premium)
ORDER BY sort1, sort2 DESC
(Ob man den Zufall auf- oder absteigend sortiert, ist egal, Hauptsache der Timestamp kommt in der gewünschten Reihenfolge.)
Lo!