Guide: Ordine con valori null ultimo

Nella mia applicazione Rails ho un problema un paio di volte che mi piacerebbe sapere come altre persone a risolvere:

Ho certo i record in cui il valore è opzionale, quindi alcuni record che hanno un valore e alcuni sono null colonna.

Se faccio un ordine da quella colonna nel database i valori null sorta di prima e su alcuni database i valori null ordinamento ultimo.

Per esempio, mi sono Foto che possono o non possono far parte di una Collezione, cioè ci sono alcune Foto in cui collection_id=nil e un po ‘ dove collection_id=1 etc.

Se faccio Photo.order('collection_id desc) poi su SQLite ottenere i valori null in ultimo, ma su PostgreSQL ho l’null primo.

C’è una bella guida profilata modo di gestire questo e ottenere prestazioni costanti su qualsiasi database?

OriginaleL’autore Andrew | 2011-04-28

11 Replies
  1. 5

    Aggiunta di matrici insieme per mantenere l’ordine:

    @nonull = Photo.where("collection_id is not null").order("collection_id desc")
    @yesnull = Photo.where("collection_id is null")
    @wanted = @nonull+@yesnull

    http://www.ruby-doc.org/core/classes/Array.html#M000271

    Beh, non mi piace questa idea, ma penso che dovrebbe funzionare. Dispiace aver lasciato aperto così a lungo, spero che altre risposte sembrerebbe. Dopo aver trascorso qualche tempo più a pensare, però, penso che questo potrebbe essere fatto in un metodo sul modello di Fotografia e quindi non si sentono troppo male.
    È facile se si utilizza mysql. Vedere la mia soluzione.
    A destra, mi hanno detto che la mia era solo il più agnostico modo che ho potuto trovare.
    Questa è una cattiva idea, dato che where non restituisce un array e restituisce un ActiveRecord::Relazione e costringendo i risultati in un array causa tutto che si aspetta un standard ActiveRecord::Relazione a fallire (come l’impaginazione).
    Vero, anche se sembra che la disposizione metodi di rompere AR o non sono (completamente) portatile.

    OriginaleL’autore Eric

  2. 216

    Non sono un esperto di SQL, ma perché non ordinare se qualcosa è null prima quindi di ordinare da come si voleva risolvere.

    Photo.order('collection_id IS NULL, collection_id DESC')  # Null's last
    Photo.order('collection_id IS NOT NULL, collection_id DESC') # Null's first

    Se si sta solo usando PostgreSQL, puoi anche farlo

    Photo.order('collection_id DESC NULLS LAST')  #Null's Last
    Photo.order('collection_id DESC NULLS FIRST') #Null's First

    Ma SQLite3 vi darà errori.

    +1, molto meglio di accettato di rispondere e può essere espresso tramite Arel
    wow, questo è un vecchio commento ! Quindi credo che quello che stavo cercando di dire è stata : p = Photo.arel_table; Photo.order(p[:collection_id].eq(nil)).order(p[:collection_id].desc)
    Nota che NULLS LAST non consente di catena .last() su query di Guide 4.2. Ho postato un work-around di seguito.
    Perché non ordinare da IS NULL mettere NULL righe? Si potrebbe pensare che sarebbe messo loro in primo luogo.
    myguess: È NULL restituisce 1 se true, 0 se falso, ordinati, 0 viene prima di 1 …

    OriginaleL’autore Intentss

  3. 25

    Anche se è il 2017, ora, c’è ancora un consenso su se NULLs dovrebbe avere la precedenza. Senza essere esplicito su di esso, i risultati variano a seconda del DBMS.

    Lo standard non specifica come Null, deve essere ordinato in confronto con i valori non NULL, eccetto il fatto che due Nulli sono da considerarsi ugualmente ordinato, e che Null dovrebbe ordinare al di sopra o al di sotto di tutti i valori non NULL.

    origine, confronto con la maggior parte dei Dbms

    Per illustrare il problema, ho compilato una lista di alcuni casi più comuni quando si tratta di Binari di sviluppo:

    PostgreSQL

    NULLs il valore più alto.

    Per impostazione predefinita, i valori null sorta, come se più grande di qualsiasi valore non nullo.

    fonte: la documentazione di PostgreSQL

    MySQL

    NULLs hanno il valore più basso.

    Quando si fa un ORDINE, i valori NULL sono presentato prima, se farete ORDINI … ASC e l’ultimo se fare l’ORDINE … DESC.

    fonte: documentazione di MySQL

    SQLite

    NULLs hanno il valore più basso.

    Una riga con un valore NULL è superiore a righe con valori regolari in ordine crescente, e si è ribaltato, per ordine decrescente.

    fonte

    Soluzione

    Purtroppo, le Rotaie non fornisce una soluzione di sicurezza.

    PostgreSQL specifiche

    Per PostgreSQL si potrebbe abbastanza intuitivo utilizzo:

    Photo.order('collection_id DESC NULLS LAST') # NULLs come last

    MySQL specifiche

    Per MySQL, si potrebbe mettere il segno meno in anticipo, ma questa caratteristica sembra essere privi di documenti. Sembra funzionare non solo con i valori numerici, ma con date.

    Photo.order('-collection_id DESC') # NULLs come last

    PostgreSQL e MySQL specifiche

    Per la copertura di entrambi, questo sembra funzionare:

    Photo.order('collection_id IS NULL, collection_id DESC') # NULLs come last

    Ancora, questo non funziona in SQLite.

    Soluzione universale

    Per fornire cross-supporto per tutti i Dbms dovresti scrivere una query che utilizza CASE, già suggerito da @PhilIT:

    Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')

    che si traduce in primo ordinamento di ciascun record prima da CASE risultati (per impostazione predefinita ordine crescente, il che significa che NULL valori sarà l’ultima volta), la seconda per calculation_id.

    OriginaleL’autore Adam Sibik

  4. 11

    Mettere segno meno davanti column_name e invertire l’ordine direzione. Funziona su mysql. Maggiori dettagli

    Product.order('something_date ASC') # NULLS came first
    Product.order('-something_date DESC') # NULLS came last
    Non funziona in Postgres

    OriginaleL’autore raymondralibi

  5. 10
    Photo.order('collection_id DESC NULLS LAST')

    So che questo è un vecchio ma ho appena trovato questo frammento di codice e funziona per me.

    OriginaleL’autore Thomas Yancey

  6. 7

    Po ‘ in ritardo per lo spettacolo, ma c’è un generico SQL modo per farlo. Come di consueto, CASE per il salvataggio.

    Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')
    Grazie mille, funziona come un fascino!

    OriginaleL’autore PhilT

  7. 6

    Per i posteri amore, ho voluto evidenziare un ActiveRecord di errore relative al NULLS FIRST.

    Se si tenta di chiamare:

    Model.scope_with_nulls_first.last

    Rails tentativo di chiamare reverse_order.first, e reverse_order non è compatibile con NULLS LAST, come si tenta di generare il codice SQL non valido:

    PG::SyntaxError: ERROR:  syntax error at or near "DESC"
    LINE 1: ...dents"  ORDER BY table_column DESC NULLS LAST DESC LIMIT...

    Questo è stato fatto riferimento a un paio di anni fa in alcuni ancora aperti Rotaie problemi (uno, due, tre). Sono riuscito a risolvere è il seguente:

      scope :nulls_first, -> { order("table_column IS NOT NULL") }
      scope :meaningfully_ordered, -> { nulls_first.order("table_column ASC") }

    Sembra che concatenando i due ordini insieme, SQL valida viene generato:

    Model Load (12.0ms)  SELECT  "models".* FROM "models"  ORDER BY table_column IS NULL DESC, table_column ASC LIMIT 1

    L’unico aspetto negativo è che questo concatenamento deve essere fatto per ogni ambito.

    OriginaleL’autore Lanny Bose

  8. 5

    Il modo più semplice è quello di utilizzare:

    .order('name nulls first')

    Questo non funziona per tutti i database.
    Questo è il modo migliore per Postgres
    Questa è una buona soluzione, ma attenzione che ActiveRecord last sembra inserisci un popolo errante DESC.

    OriginaleL’autore Jean-Etienne Durand

  9. 1

    Nel mio caso avevo bisogno di ordinare le righe da data di inizio e fine da ASC, ma in alcuni casi end_date era nulla e che le linee devono essere in precedenza, ho usato

    @invoice.invoice_lines.order('start_date ASC, end_date ASC NULLS FIRST')

    OriginaleL’autore Dmitriy Gusev

  10. -1

    Prima di ottenere Foto dove collection_id non è null e ordine da collection_id decrescente.

    Quindi ottenere Foto in cui collection_id è null e aggiungerli.

    Photos.where.not(collection_id: [nil, ""])
      .order(collection_id: :desc) + where(collection_id: [nil, ""])

    OriginaleL’autore cseelus

  11. -2

    Sembra che devi farlo in Ruby se vuoi risultati coerenti per i tipi di database, il database stesso interpreta se o non i valori NULL andare al fronte o alla fine della lista.

    Photo.all.sort {|a, b| a.collection_id.to_i <=> b.collection_id.to_i}

    Ma non è molto efficiente.

    OriginaleL’autore jaredonline

Lascia un commento