So definieren Sie eine benutzerdefinierte ORDER BY-Reihenfolge in mySQL

142

Wie definiere ich in MySQL eine benutzerdefinierte Sortierreihenfolge?

Um zu erklären, was ich möchte, betrachten Sie diese Tabelle:

ID  Language    Text
0   ENU         a
0   JPN         b
0   DAN         c       
1   ENU         d
1   JPN         e
1   DAN         f
2   etc...

Hier möchte ich alle Zeilen zurückgeben, die nach Sprache und aufsteigender ID sortiert sind, sodass zuerst Sprache = ENU, dann JPN und zuletzt DAN steht.

Das Ergebnis sollte sein: a, d, b, e, c, f usw.

Ist das überhaupt möglich?

Muleskinner
quelle

Antworten:

274

MySQL hat eine praktische Funktion namens, FIELD()die sich hervorragend für solche Aufgaben eignet.

ORDER BY FIELD(Language,'ENU','JPN','DAN'), ID

Beachten Sie jedoch, dass

  1. Dadurch wird Ihr SQL weniger portabel, da andere DBMS möglicherweise nicht über eine solche Funktion verfügen

  2. Wenn Ihre Liste der Sprachen (oder anderer Werte, nach denen sortiert werden soll) viel länger wird, ist es besser, eine separate Tabelle mit einer Sortierreihenfolge für sie zu haben und diese zur Bestellung mit Ihren Abfragen zu verknüpfen.

Mchl
quelle
3
Vielen Dank, dies ist perfekt für meine Situation, in der ich nur nach zwei Werten ordnen muss (eine Primärsprache, zum Beispiel JPN, und eine Fallback-Sprache, zum Beispiel ENU).
Muleskinner
4
Mann, du hast mir gerade ein Umschreiben in Magento erspart :)
Erik Simonic
1
Was ist, wenn Sie eine GROUP BYvorher haben? Zum Beispiel erscheint der erste gewünschte Wert am Ende?
Pathros
GROUP BYFügen Sie die Abfrage mit in eine Unterabfrage ein und ordnen Sie sie in der äußeren Abfrage an
Mchl
1
Arbeite wie ein Zauber :)
Brane
53

Wenn dies die einzigen drei Werte sind, können Sie einen CASEAusdruck verwenden :

ORDER BY `ID`,
         CASE `Language`
         WHEN 'ENU' THEN 1
         WHEN 'JPN' THEN 2
         WHEN 'DAN' THEN 3
         END

(Wenn es andere Werte geben könnte, möchten Sie möglicherweise eine zusätzliche Logik hinzufügen, um die Reihenfolge konsistent zu halten. Sie können beispielsweise ELSE 4diesen CASEAusdruck hinzufügen und dann Languageals drittes Ordnungskriterium selbst sortieren:

ORDER BY `ID`,
         CASE `Language`
         WHEN 'ENU' THEN 1
         WHEN 'JPN' THEN 2
         WHEN 'DAN' THEN 3
         ELSE 4
         END,
         `Language`

)

Ruakh
quelle
1
Und wenn es viele Sprachwerte gibt, könnten Sie eine separate Tabelle haben, in der jede Sprache gespeichert ist, sowie eine Spalte für die Sortierreihenfolge und einen Link dazu
kaj
1
Dies wird zuerst nach ID sortiert, was zu a, b, c, d, e, f
piotrm
Danke, das funktioniert perfekt - ebenso wie die Antwort von Mchl, die ich akzeptiert habe, da sie einfacher aussieht
Muleskinner
19

Sie haben sofort mehrere Optionen. Die erste besteht darin, die Sprache in ENUM zu ändern (vorausgesetzt, dies ist möglich und Sie erwarten nur wenige Variationen).

Wenn Sie es angeben , wie ENUM('ENU','JPN','DAN')dann ORDER Language ASCwerden Sie in der Reihenfolge angeben bestellen.

Der zweite wird irgendwo einen Fall betreffen, dh

SELECT * FROM table
ORDER BY CASE Language
    WHEN 'ENU' THEN 3
    WHEN 'JPN' THEN 2
    WHEN 'DAN' THEN 1
    ELSE 0
END DESC, ID ASC

In Bezug auf die Leistung liefert die ENUM-Methode schnellere Ergebnisse, ist jedoch problematischer, wenn Sie weitere Sprachen hinzufügen müssen. Eine dritte Option wäre das Hinzufügen einer Normalisierungstabelle für die Sprachen, die in diesem Fall jedoch möglicherweise übertrieben ist.

Simon bei My School Portal
quelle
Wo genau tippst du ENUM('ENU','JPN','DAN')?
Pathros
1
@pathros in der Tabellendefinition geben Sie es als ENUM anstelle von VARCHAR usw. an. Intern speichert MySQL die ENUM-Optionen in einer bestimmten Reihenfolge und indiziert sie. Wenn Sie also speziell nach einer ENUM-Spalte bestellen, wird dieser interne Index anstelle des verwendet Zeichenfolgenwerte (es sei denn, CAST () wird verwendet, um zu einem VARCHAR zurückzukehren)
Simon bei My School Portal
Sollte nicht END DESC,sein END CASE DESC,?
Istiaque Ahmed
Nee. Nicht alle CASEbrauchen END CASE, es hängt vom Kontext ab. CASEinnerhalb von PROCEDURE erfordern END CASE( dev.mysql.com/doc/refman/5.5/en/case.html ), jedoch CASEinnerhalb von SELECT nicht erforderlich END CASE, einfach END( dev.mysql.com/doc/refman/5.7/en/… ) - in diesem Kontext ist es eine Kontrollflussfunktion.
Simon bei My School Portal
1

Für das Yii2-Framework können wir Folgendes erreichen

Project::find()
->orderBy([new Expression('FIELD(pid_is_t_m,2,0,1)'),'task_last_work'=> SORT_ASC])
->all();
Prahlad
quelle