sql ORDINA PER più valori in un ordine specifico?


94

Ok ho una tabella con una chiave indicizzata e un campo non indicizzato. Devo trovare tutti i record con un certo valore e restituire la riga. Vorrei sapere se posso ordinare in base a più valori.

Esempio:

id     x_field
--     -----
123    a
124    a
125    a
126    b
127    f
128    b
129    a
130    x
131    x
132    b
133    p
134    p
135    i

pseudo: vorrebbe che i risultati fossero ordinati in questo modo, where ORDER BY x_field = 'f', 'p', 'i', 'a'

SELECT *
FROM table
WHERE id NOT IN (126)
ORDER BY x_field 'f', 'p', 'i', 'a'

Quindi i risultati sarebbero:

id     x_field
--     -----
127    f
133    p
134    p
135    i
123    a
124    a
125    a
129    a

La sintassi è valida ma quando eseguo la query non restituisce mai alcun risultato, anche se la limito a 1 record. C'è un altro modo per farlo?

Pensa al campo x come ai risultati del test e ho bisogno di convalidare tutti i record che rientrano nella condizione. Volevo ordinare i risultati del test in base a valori non riusciti, valori passati. Quindi ho potuto convalidare prima i valori non riusciti e poi i valori passati usando ORDER BY.

Cosa non posso fare:

  • GROUP BY, poiché ho bisogno di restituire i valori record specifici
  • WHERE x_field IN ('f', 'p', 'i', 'a'), ho bisogno di tutti i valori poiché sto cercando di utilizzare una query per diversi test di convalida. E i valori x_field non sono nell'ordine DESC / ASC

Dopo aver scritto questa domanda sto iniziando a pensare che devo ripensare a questo, LOL!


Forse un sindacato invece? Costruisci query separate nell'ordine in cui desideri restituire i risultati, quindi fai un'unione di quelle query?
kinakuta

Risposte:


181
...
WHERE
   x_field IN ('f', 'p', 'i', 'a') ...
ORDER BY
   CASE x_field
      WHEN 'f' THEN 1
      WHEN 'p' THEN 2
      WHEN 'i' THEN 3
      WHEN 'a' THEN 4
      ELSE 5 --needed only is no IN clause above. eg when = 'b'
   END, id

29

Puoi utilizzare LEFT JOIN con "VALUES ('f', 1), ('p', 2), ('a', 3), ('i', 4)" e utilizzare la seconda colonna nel tuo ordine -da espressione. Postgres utilizzerà un Hash Join che sarà molto più veloce di un enorme CASE se hai molti valori. Ed è più facile generare automaticamente.

Se queste informazioni sull'ordine sono corrette, dovrebbe avere una propria tabella.


6
Questa è in assoluto la soluzione più elegante!
jnns

28

Provare:

ORDER BY x_field='F', x_field='P', x_field='A', x_field='I'

Eri sulla strada giusta, ma mettendo x_field solo sul valore F, gli altri 3 sono stati trattati come costanti e non confrontati con nulla nel set di dati.


Postgres supporta il booleano implicito? In tal caso, come funziona l'ordinamento booleano?
gbn

Questa soluzione mi è piaciuta ma non ha restituito nulla.
Phill Pafford

@gbn, Sì e false <true. Mi sarei aspettato che funzionasse.
Andrew Lazarus

7
Sì, funziona l'evento in Postgres. Nota per questa soluzione è che ottieni risultati ordinati in ordine inverso. Quindi devi mettere i campi in ordine inverso: ORDER BY x_field = 'A', x_field = 'I', x_field = 'P', x_field = 'F',
igo

16

Utilizza un caseinterruttore per tradurre i codici in numeri che possono essere ordinati:

ORDER BY
  case x_field
  when 'f' then 1
  when 'p' then 2
  when 'i' then 3
  when 'a' then 4
  else 5
  end

10

Ho trovato una soluzione molto più pulita per questo:

ORDER BY array_position(ARRAY['f', 'p', 'i', 'a']::varchar[], x_field)

Nota: array_position richiede Postgres v9.5 o superiore.


1
È importante notare che array_position () è disponibile solo in Postgres v9.5 in poi, afaik.
bigsee

grazie, preferisco di gran lunga questo ai metodi CASE. Funziona anche con numeri interi; array_position(ARRAY[1, 0]::integer[], x_field)
Paul Watson,

7

I suggerimenti CASEe ORDER BYdovrebbero funzionare tutti, ma suggerirò un cavallo di un colore diverso. Supponendo che ci sia solo un numero ragionevole di valori per x_fielde tu sai già cosa sono, crea un tipo enumerato con F, P, A e I come valori (più qualsiasi altro possibile valore applicabile). Gli enum verranno ordinati nell'ordine implicito da loroCREATE dichiarazione. Inoltre, è possibile utilizzare nomi di valori significativi (probabilmente la tua applicazione reale lo fa e li hai appena mascherati per riservatezza) senza sprecare spazio, poiché viene memorizzata solo la posizione ordinale.


1

Puoi ordinare in base a una colonna selezionata o ad altre espressioni.

Ecco un esempio, come ordinare in base al risultato di un'istruzione case:

  SELECT col1
       , col2
    FROM tbl_Bill
   WHERE col1 = 0
ORDER BY -- order by case-statement
    CASE WHEN tbl_Bill.IsGen = 0 THEN 0
         WHEN tbl_Bill.IsGen = 1 THEN 1
         ELSE 2 END

Il risultato sarà un elenco che inizia con le righe "IsGen = 0", seguito dalle righe "IsGen = 1" e tutte le altre righe alla fine.

Potresti aggiungere più parametri dell'ordine alla fine:

  SELECT col1
       , col2
    FROM tbl_Bill
   WHERE col1 = 0
ORDER BY -- order by case-statement
    CASE WHEN tbl_Bill.IsGen = 0 THEN 0
         WHEN tbl_Bill.IsGen = 1 THEN 1
         ELSE 2 END,
         col1,
         col2

Sebbene questo frammento di codice possa risolvere il problema, non spiega perché o come risponde alla domanda. Per favore includi una spiegazione per il tuo codice , in quanto aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro e quelle persone potrebbero non conoscere i motivi del tuo suggerimento sul codice.
Samuel Philipp

0

Per qualcuno che è nuovo su ORDER BY con CASE questo può essere utile

ORDER BY 
    CASE WHEN GRADE = 'A' THEN 0
         WHEN GRADE = 'B' THEN 1
         ELSE 2 END

-2

è possibile utilizzare la posizione (testo nel testo) per ordinare la sequenza

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.