2010-11-03 12 views
31

L'ho trovato qualche tempo fa e da allora lo sto usando; tuttavia, osservandolo oggi, mi sono reso conto che non capisco del tutto perché funzioni. Qualcuno può far luce su di esso per me?Custom ORDER BY Spiegazione

ORDER BY s.type!= 'Nails', 
      s.type!= 'Bolts', 
      s.type!= 'Washers', 
      s.type!= 'Screws', 
      s.type!= 'Staples', 
      s.type!= 'Nuts', ... 

Se ordino da s.type, ordina alfabeticamente. Se uso l'esempio sopra, usa lo stesso ordine delle posizioni di linea. Quello che non capisco è l'uso di! =. Se uso = appare nell'ordine opposto. Non riesco a comprendere il concetto di questo.

Sarebbe logico per me che l'utilizzo di = al posto di! = 'In alto posizionasse le Unghie prima in posizione, ma non lo posiziona, lo inserisce nell'ultimo. Credo che la mia domanda sia questa: Perché devo usare! =, Non = in questa situazione?

+14

Quindi, se non capisco qualcosa, anche se mi piace l'eleganza e la semplicità di una soluzione, dovrei tenere le mani sulle orecchie e ripetere "La, la, la ". Non mi piace questo approccio; Preferirei imparare qualcosa di nuovo e mettermi a mio agio. –

risposta

23

Non l'ho mai visto ma sembra avere senso.

All'inizio ordina per s.type != 'Nails'. Questo è false per ogni riga che contiene Nails nella colonna type. Dopo questo è ordinato per Bolts. Anche in questo caso per tutte le colonne che contengono Bolts come type questo valore è falso. E così via.

Un piccolo test rivela che false è ordinato prima true. Quindi hai il seguente: per prima cosa ottieni tutte le righe con Nails in cima perché il ORDER BY secondo valutato a false e false viene prima. Le restanti righe sono ordinate secondo il secondo criterio ORDER BY. E così via.

 
type  | != Nails | != Bolts | != Washers 
'Nails' | false | true  | true 
'Bolts' | true  | false | true 
'Washers' | true  | true  | false 
+1

Non dimenticare i valori NULL. –

+1

Questo è puramente un pensiero. Ma suppongo che ordini falsi prima del vero, a causa dei loro valori interi rispettati di 0 e 1 dove 0 (falso) viene prima di 1 (vero). –

41

Ogni espressione viene valutata come bool e trattato come 0 per falso e 1 per vero e allineati in modo appropriato. Anche se questo funziona, la logica è difficile da seguire (e quindi mantenere). Quello che uso è una funzione che trova l'indice di un valore in una matrice.

ORDER BY idx(array['Nails','Bolts','Washers','Screws','Staples','Nuts'], s.type) 

Questo è molto più facile da seguire. I chiodi verranno ordinati per primi e i dadi saranno ordinati per ultimi. Puoi vedere come creare la funzione idx nel repository dei frammenti di Postgres. http://wiki.postgresql.org/wiki/Array_Index

+2

dovrebbe essere 'matrice_position' –

+1

@EbenGeer solo su 9.5 e oltre – DarkMukke

15

@Scott Bailey suggerito grande idea. Ma può essere anche più semplice (non devi creare funzioni personalizzate) da PostgreSQL 9.5. Basta usare la funzione array_position:

ORDER BY array_position(array['Nails','Bolts','Washers','Screws','Staples','Nuts'], s.type) 
+0

Questa risposta mi ha fatto risparmiare un sacco di lavoro. Grazie! –

+0

l'ho provato nella mia istanza di sviluppo, è stato ottimo, la produzione è ancora in 9.3 ..non così grande – DarkMukke

+2

Questo vale per le colonne di tipo 'Testo', ho provato questo con un tipo di colonna' carattere' e la funzione ha gettato un errore - si spera che questo aiuti :) –

1

con array_position, ha bisogno di avere lo stesso tipo che si sta interrogando contro.

esempio:

select array_position(array['foo'::char,'bar','baz'::char], 'bar'); 
select array_position(array['foo'::char,'bar','baz'::char], 'baz'::char);