Mengapa NULL diurutkan terlebih dahulu?


20

Mengapa ketika kami memiliki nilai NULL dalam kolom dan kami memesan berdasarkan nilai yang naik, NULL diurutkan terlebih dahulu?

select 1 as test
union all
select 2
union all
select NULL
union all
select 3
union all
select 4
order by test

hasil dalam

NULL
1
2
3
4

Saya terus berpikir bahwa NULL berarti "Tidak Pasti" atau mungkin "Tidak Diketahui". Jika itu benar, bukankah mereka akan mengurutkan terakhir, karena nilainya bisa lebih besar dari semua nilai lainnya? (Atau ini pilihan sortir?)

Saya menggunakan SQL Server 2008R2, tetapi saya menduga ini benar di semua SQL Server, dan mungkin di semua RDBMS.


1
Oracle mendaftar paling akhir. Itu mengacaukan saya sekali, percaya itu harus berperilaku seperti SQL Server.
Andrei Rînea

2
"Jika itu benar, bukankah mereka akan menyortir terakhir, karena nilainya bisa lebih besar dari semua nilai lainnya". Nilainya bisa kurang dari semua nilai lainnya juga. Bagi saya, itu intuitif bahwa nilai falsey seperti null harus di ujung bawah. Dan praktis, karena dalam praktiknya, Anda sering ingin menggunakan descpemesanan untuk menunjukkan hal-hal terbesar atau terbaru, dalam hal ini saya akan senang jika hal-hal nol menjadi yang terakhir.
mahemoff

Basis data melakukan apa yang Anda perintahkan. Jika Anda tahu bahwa data Anda berisi nol dan Anda memiliki alasan bisnis untuk menyortir data dengan cara tertentu, maka Anda perlu menentukannya dalam kueri atau kode / tampilan yang memproses / menampilkan data. Jangan sekali-kali menyortir perilaku database default.
nothingisnecessary

Jawaban:


19

BOL : Nilai NULL menunjukkan bahwa nilainya tidak diketahui. Nilai NULL berbeda dari nilai kosong atau nol. Tidak ada dua nilai nol yang sama. Perbandingan antara dua nilai nol, atau antara NULL dan nilai lainnya, menghasilkan tidak diketahui karena nilai setiap NULL tidak diketahui.

NULL berarti tidak dikenal. Tidak ada interpretasi lain yang valid.

Jika itu benar, bukankah mereka akan mengurutkan terakhir, karena nilainya bisa lebih besar dari semua nilai lainnya?

Tidak mungkin ada . Tidak ada nilai potensial . Tidak dikenal tidak diketahui tidak diketahui.

Mengenai mengapa ini muncul pertama kali, bukan yang terakhir, ini tidak dipenuhi oleh standar SQL yang dipublikasikan dan sayangnya diserahkan kepada kebijaksanaan vendor RDBMS:

Wikipedia : Standar SQL tidak secara eksplisit mendefinisikan urutan urutan default untuk Nulls. Sebaliknya, pada sistem yang menyesuaikan, Nulls dapat diurutkan sebelum atau setelah semua nilai data dengan menggunakan klausa NULLS FIRST atau NULLS LAST dari daftar ORDER BY, masing-masing. Namun, tidak semua vendor DBMS menerapkan fungsi ini. Vendor yang tidak menerapkan fungsi ini dapat menentukan perawatan yang berbeda untuk pengurutan Null di DBMS.


Jadi, ini panggilan penilaian. Itu sangat masuk akal. Terima kasih!
Richard

6

Anda benar yang NULLdapat berarti 'Tidak Menentu' atau 'Uknownn' atau 'Belum dikenal' atau 'Tidak mendaftar'. Tetapi tidak ada alasan untuk menempatkan Nulls sebagai yang pertama atau terakhir. Jika kita tidak tahu nilai sebenarnya, maka itu bisa kecil atau besar.

Saya pikir standar untuk menentukan perilaku yang diinginkan Nulls selama penyortiran, adalah:

ORDER BY 
    test NULLS LAST                      --- or NULLS FIRST for the opposite

Sayangnya SQL-Server belum mengadopsi sintaks ini. Jika saya tidak salah, PostgreSQL dan Oracle memilikinya.

Satu solusi:

ORDER BY 
     CASE WHEN test IS NOT NULL 
            THEN 0 
          ELSE 1 
     END 
   , test

Solusi lain yang perlu penyesuaian tergantung pada tipe data - tetapi tidak akan terbentuk dengan baik, karena tidak dapat menggunakan indeks pada (test):

ORDER BY 
    COALESCE(test, 2147483647)               --- if it's a 4-byte signed integer

Dengan cara ini ORDER BY COALESCE (test, 2147483647) SQL server tidak dapat menggunakan Indeks.
Ardalan Shahgholi

3

Saya tidak tahu mengapa itu dilakukan seperti itu, tetapi menurut definisi NULLS tidak dapat dibandingkan dengan non-NULLS, sehingga mereka harus pergi di awal atau di akhir (jawaban Markus membahas hal ini dengan lebih detail).

Untuk mendapatkan perilaku yang Anda inginkan - Sejauh yang saya tahu tidak ada opsi penyortiran untuk menempatkan nulls terakhir, jadi Anda harus menggabungkannya dengan menggunakan kolom yang dikomputasi untuk memaksa mereka bertahan. Namun, dalam SQL Server Anda tidak dapat memesan dengan kolom yang dihitung ( CASE WHEN ...) ketika data Anda berisi operator yang ditetapkan ( UNION ALL). Begitu:

CREATE TABLE #sorttest(test int)
INSERT INTO #sorttest values(1)
INSERT INTO #sorttest values(5)
INSERT INTO #sorttest values(4)
INSERT INTO #sorttest values(NULL)
INSERT INTO #sorttest values(3)
INSERT INTO #sorttest values(2)
SELECT test
FROM #sorttest
ORDER BY CASE WHEN test IS NULL THEN 1 ELSE 0 END, test

DROP TABLE #sorttest

Akan bekerja untuk menyortir null yang terakhir. Jika Anda harus menggunakan UNION(atau EXCEPTatau INTERSECTS) untuk menghasilkan kumpulan data Anda, maka buang data Anda ke tabel sementara seperti di atas.


... atau gunakan output UNIONed sebagai tabel turunan.
Andriy M

0

Jika Anda berurusan dengan angka, Anda juga dapat menggunakan

ORDER BY -test DESC

NULLadalah nilai serendah mungkin, oleh karena itu DESCmenempatkan mereka pada akhirnya. Sementara itu nilai-nilai bukan nol memiliki tanda terbalik sehingga DESCsebenarnya adalah ASCpada nilai-nilai nyata. Ini harus lebih cepat daripada CASEdan saya kira optimizer kueri juga dapat menggunakan indeks pada testkolom.


3
Tidak, itu tidak akan dapat menggunakan indeks untuk semacam itu. Kecuali Anda memiliki indeks pada ekspresi yang dihitung (- test).
ypercubeᵀᴹ

1
Pintar, meskipun terbatas pada data numerik saja (sesuai untuk contoh OP). Saya tidak yakin apakah ini memang akan lebih cepat daripada menggunakan KASUS tapi saya yakin itu tidak akan menggunakan indeks (kecuali jika itu yang dikatakan @ ypercubeᵀᴹ - tapi kemudian ekspresi KASUS dapat diindeks dengan cara yang persis sama).
Andriy M
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.