SQL cara membuat nilai nol menjadi yang terakhir saat menyortir naik

297

Saya punya tabel SQL dengan bidang datetime. Bidang yang dimaksud dapat berupa nol. Saya punya pertanyaan dan saya ingin hasil diurutkan secara naik-turun oleh bidang datetime, namun saya ingin baris di mana bidang datetime adalah nol di akhir daftar, bukan di awal.

Apakah ada cara sederhana untuk mencapainya?

David Božjak
sumber

Jawaban:

394
select MyDate
from MyTable
order by case when MyDate is null then 1 else 0 end, MyDate
RedFilter
sumber
2
Perhatikan bahwa jika Anda menempatkan indeks pada kolom sortir untuk meningkatkan kinerja (*), maka metode ini akan sedikit memperumit rencana kueri dan kehilangan banyak manfaat kinerja. * - indeks menyediakan data yang diprioritaskan, karenanya menghindari semacam per eksekusi permintaan. Dianjurkan untuk memfilter catatan NULL jika memungkinkan untuk menghindari masalah ini sepenuhnya.
redcalx
2
Jawaban yang baik juga diberikan di sini dengan semua cara yang mungkin dengan keuntungan dan kerugian nickstips.wordpress.com/2010/09/30/…
sudhAnsu63
40
order by case when MyDate is null then 1 else 0 endadalah cara yang sangat panjang untuk mengatakanORDER BY MyDate IS NULL
Martin
5
@ Martin Perhatikan pertanyaan ini tidak ditandai mysql. Saya memberikan solusi umum - ada banyak cara berbeda untuk melakukan hal yang sama di berbagai dbs.
RedFilter
1
@KyleDelaney Karena order by 0ditafsirkan sebagai indeks kolom, dan indeks kolom berbasis 1. Untuk mengurutkan kueri menurut kolom ke-3 Anda bisa mengatakan order by 3(yang merupakan ide buruk untuk permintaan produksi), tetapi sangat berguna (seperti *) saat bereksperimen.
RedFilter
159

(Sedikit "terlambat", tetapi ini belum disebutkan sama sekali)

Anda tidak menentukan DBMS Anda.

Dalam SQL standar (dan kebanyakan DBMS modern seperti Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB, dan H2) Anda dapat menentukan NULLS LASTatau NULLS FIRST:

Gunakan NULLS LASTuntuk mengurutkan mereka sampai akhir:

select *
from some_table
order by some_column DESC NULLS LAST
seekor kuda tanpa nama
sumber
16
AFAIK NULLS FIRSTdan NULLS LASTtelah ditambahkan dalam SQL: 2003 tetapi tidak ada implementasi standar yang tersedia di seluruh DMBS berbeda. Tergantung pada mesin database, gunakan ORDER BY expr some_column DESC NULLS LAST(Oracle), ORDER BY ISNULL(some_column, 1), some_column ASC(MSSQL) atau ORDER BY ISNULL(some_column), some_column ASC(MySQL dengan implementasi ISNULL () yang berbeda).
SaschaM78
3
@ SaschaM78: penyortiran default NULL adalah DBMS dependen. Beberapa mengurutkannya di akhir, beberapa di awal. Beberapa tidak peduli tentang ASC/ DESCdengan nulls beberapa lakukan. Jadi satu-satunya cara untuk memastikan ini, adalah menggunakan NULL FIRST/LAST jika DBMS mendukungnya. Itu mendokumentasikan apa yang Anda inginkan. Penggunaan isnull()atau fungsi lainnya adalah solusi untuk dukungan yang hilang untuk NULLS FIRST/LAST(yang didukung oleh Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB dan H2)
a_horse_with_no_name
Anda benar sekali, saya hanya ingin menambahkan fakta bahwa ada beberapa DBMS di sekitar yang tidak mengikuti standar (belum) atau memiliki spesialisasi mereka seperti Oracle yang membutuhkan exprkata kunci saat menggunakan NULLS FIRST / LAST. Dan terima kasih tentang nulls yang ditampilkan pertama / terakhir bervariasi dari tipe database ke tipe, tidak tahu itu!
SaschaM78
2
Ini terlihat menjanjikan, tetapi sayangnya, saya mencobanya dan NULLS LASTtidak berfungsi di database MySQL saya.
AdmiralThrawn
1
@AdmiralAdama: Anda selalu dapat meningkatkan ke Postgres
a_horse_with_no_name
35

Saya juga menemukan ini dan berikut ini sepertinya melakukan trik untuk saya, pada MySQL dan PostgreSQL:

ORDER BY date IS NULL, date DESC

seperti yang ditemukan di https://stackoverflow.com/a/7055259/496209

Luksurious
sumber
Ini terlihat menjanjikan, tetapi sayangnya, saya mencobanya IS NULLdan IS NOT NULLtidak berhasil di database MySQL saya.
AdmiralThrawn
14
order by coalesce(date-time-field,large date in future)
Gratzy
sumber
10
Meskipun ini umumnya akan berhasil, perlu dicatat bahwa jawaban ini memiliki beberapa masalah: tanggal yang besar di masa depan mungkin bertabrakan dengan atau kurang dari data aktual, menghasilkan jenis yang tidak sempurna. Juga, ini adalah solusi "angka ajaib" yang tidak mendokumentasikan diri.
RedFilter
Ini kebetulan menjadi alternatif yang bagus untuk jawaban @RedFilter ketika Anda perlu membandingkan kolom yang dimaksud dengan kolom tanggal lainnya. Saya menggunakan ini untuk daftar senioritas serikat. Jika karyawan memiliki tanggal Terkualifikasi (yang tidak dapat dibatalkan), tanggal tersebut akan merekam ke atas, jika tidak gunakan HireDate. Menggunakan ORDER OLEH ISNULL (QualifiedDate, '1-1-2099'), HireDate, LastName, dll. Membuat tanggal Berkualitas tidak bertentangan dengan tanggal HiredDate dan daftar senirity yang benar diproduksi.
Alan Fisher
14

Anda dapat menggunakan fungsi bawaan untuk memeriksa nol atau tidak, seperti di bawah ini. Saya mengujinya dan berfungsi dengan baik.

select MyDate from MyTable order by ISNULL(MyDate,1) DESC, MyDate ASC;

Majdi M. Aburahelah
sumber
Untuk tanggal bekerja dengan mssql saya menemukan berguna menempatkan jauh di masa depan dalam fungsi ISNULL yaitu ISNULL (MyDate, '2100-01-01')
Emi-C
Di MySQL, dikatakan saya melewati terlalu banyak parameter. Saya mendapatkan ini untuk diuraikan dengan melakukan ISNULL(MyDate) DESC, MyDate ASC, tetapi tidak mengurutkan dalam urutan yang benar.
AdmiralThrawn
12

Jika mesin Anda memungkinkan ORDER BY x IS NULL, xatau ORDER BY x NULLS LASTmenggunakannya. Tetapi jika tidak, ini mungkin membantu:

Jika Anda mengurutkan berdasarkan tipe numerik, Anda dapat melakukan ini: (Meminjam skema dari jawaban lain .)

SELECT *          
FROM Employees
ORDER BY ISNULL(DepartmentId*0,1), DepartmentId;

hasil menunjukkan diurutkan berdasarkan DepartmentId dengan nol terakhir

Setiap angka yang bukan nol menjadi 0, dan nol menjadi 1, yang merupakan jenis nol yang terakhir.

Anda juga dapat melakukan ini untuk string:

SELECT *
FROM Employees
ORDER BY ISNULL(LEFT(LastName,0),'a'), LastName

hasil menunjukkan diurutkan berdasarkan NamaBelakang dengan angka nol yang terakhir

Karena 'a'> ''.

Ini bahkan bekerja dengan tanggal dengan memaksa ke int nullable dan menggunakan metode untuk int di atas:

SELECT *
FROM Employees
ORDER BY ISNULL(CONVERT(INT, HireDate)*0, 1), HireDate

(Mari kita berpura-pura skema memiliki HireDate.)

Metode ini menghindari masalah harus datang dengan atau mengelola nilai "maksimum" dari setiap jenis atau memperbaiki kueri jika tipe data (dan maksimum) berubah (kedua masalah yang diderita oleh solusi ISNULL lain). Plus mereka jauh lebih pendek daripada KASUS.

infogulch
sumber
Bagus sekali! Terima kasih
Vani
8

Saat kolom pesanan Anda berupa angka (seperti peringkat), Anda dapat mengalikannya dengan -1 dan kemudian memesan menurun. Ini akan menjaga urutan yang Anda harapkan tetapi menempatkan NULL sebagai yang terakhir.

select *
from table
order by -rank desc
Luizgrs
sumber
Baru saja akan berkomentar ini. Belajar dari stackoverflow.com/a/8174026/1193304 dan ini luar biasa
Chris
4
SELECT *          
FROM Employees
ORDER BY ISNULL(DepartmentId, 99999);

Lihat posting blog ini .

pengguna3923117
sumber
3

Terima kasih RedFilter untuk memberikan solusi yang sangat baik untuk masalah penyortiran bidang pengurutan data nullable.

Saya menggunakan database SQL Server untuk proyek saya.

Mengubah nilai nol datetime ke '1' memang memecahkan masalah pengurutan untuk kolom datatype datetime. Namun jika kita memiliki kolom dengan selain datatype maka gagal untuk menangani.

Untuk menangani semacam kolom varchar, saya mencoba menggunakan 'ZZZZZZZ' karena saya tahu kolom tidak memiliki nilai yang dimulai dengan 'Z'. Itu bekerja seperti yang diharapkan.

Pada baris yang sama, saya menggunakan nilai maks +1 untuk int dan tipe data lainnya untuk mendapatkan pengurutan seperti yang diharapkan. Ini juga memberi saya hasil seperti yang diminta.

Namun, selalu ideal untuk mendapatkan sesuatu yang lebih mudah di mesin basis data itu sendiri yang dapat melakukan sesuatu seperti:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

Seperti disebutkan dalam jawaban yang diberikan oleh a_horse_with_no_name.

Kasim Husaini
sumber
3

Di Oracle, Anda dapat menggunakan NULLS FIRSTatau NULLS LAST: menetapkan bahwa nilai NULL harus dikembalikan sebelum / setelah nilai bukan NULL:

ORDER BY { column-Name | [ ASC | DESC ] | [ NULLS FIRST | NULLS LAST ] }

Sebagai contoh:

ORDER BY date DESC NULLS LAST

Ref: http://docs.oracle.com/javadb/10.8.3.0/ref/rrefsqlj13658.html

Joaquinglezsantos
sumber
3

Jika Anda menggunakan MariaDB, mereka menyebutkan hal berikut dalam dokumentasi Nilai NULL .

Memerintah

Saat Anda memesan oleh bidang yang mungkin berisi nilai NULL, setiap NULL dianggap memiliki nilai terendah. Jadi pemesanan dalam urutan DESC akan melihat NULL muncul terakhir. Untuk memaksa NULL dianggap sebagai nilai tertinggi, seseorang dapat menambahkan kolom lain yang memiliki nilai lebih tinggi ketika bidang utama NULL. Contoh:

SELECT col1 FROM tab ORDER BY ISNULL(col1), col1;

Urutan menurun, dengan NULL pertama:

SELECT col1 FROM tab ORDER BY IF(col1 IS NULL, 0, 1), col1 DESC;

Semua nilai NULL juga dianggap setara untuk keperluan klausa DISTINCT dan GROUP BY.

Di atas menunjukkan dua cara untuk memesan dengan nilai NULL, Anda dapat menggabungkan ini dengan kata kunci ASC dan DESC juga. Misalnya cara lain untuk mendapatkan nilai NULL terlebih dahulu adalah:

SELECT col1 FROM tab ORDER BY ISNULL(col1) DESC, col1;
--                                         ^^^^
3limin4t0r
sumber
2

Solusi menggunakan "case" bersifat universal, tetapi jangan gunakan indeks.

order by case when MyDate is null then 1 else 0 end, MyDate

Dalam kasus saya, saya membutuhkan kinerja.

 SELECT smoneCol1,someCol2  
 FROM someSch.someTab
 WHERE someCol2 = 2101 and ( someCol1 IS NULL ) 
  UNION   
 SELECT smoneCol1,someCol2
 FROM someSch.someTab
 WHERE someCol2 = 2101 and (  someCol1 IS NOT NULL)  
Adam111p
sumber
1
Jika Anda tertarik dengan kinerja yang seharusnya Anda gunakan UNION ALL.
RedFilter
0
order by -cast([nativeDateModify] as bigint) desc
paparazzo
sumber