SQL artan değer sıralanırken null değerlerin son haline nasıl getirilir


297

Bir datetime alanı olan bir SQL tablo var. Söz konusu alan boş olabilir. Ben bir sorgu var ve ben datetime alan tarafından artan şekilde sıralanan sonuçları istiyorum, ancak datetime alan listenin sonunda değil başında null olduğu satırları istiyorum.

Bunu başarmanın basit bir yolu var mı?



Yanıtlar:


394
select MyDate
from MyTable
order by case when MyDate is null then 1 else 0 end, MyDate

2
Ancak, performansı iyileştirmek için sıralama sütununa bir dizin yerleştirirseniz (*), bu yöntemin sorgu planını biraz karmaşıklaştıracağını ve performans avantajının çoğunu kaybedeceğini unutmayın. * - dizinler veriyi sunmuş, böylece sorgu yürütme başına bir sıradan kaçınmıştır. Bu sorunu tamamen önlemek için mümkünse NULL kayıtların filtrelenmesi önerilir.
redcalx

2
Ayrıca burada avantaj ve dezavantajları olan tüm olası yollarla güzel bir cevap verilmiş nickstips.wordpress.com/2010/09/30/…
sudhAnsu63 12:13

40
order by case when MyDate is null then 1 else 0 endsöylemenin çok uzun bir yoluORDER BY MyDate IS NULL
Martin

5
@Martin Bu sorunun mysql olarak etiketlenmediğini unutmayın. Genelleştirilmiş bir çözüm sağladım - aynı şeyi farklı dbs'de yapmanın birçok farklı yolu var.
RedFilter

1
@KyleDelaney Çünkü order by 0bir sütun dizini olarak yorumlanır ve sütun dizinleri 1 tabanlıdır. Bir sorguyu 3. sütuna göre sıralamak order by 3için (üretim sorguları için korkunç bir fikirdir), ancak *deneme yaparken çok kullanışlı (olduğu gibi ) diyebilirsiniz .
RedFilter

159

(Geç kaldı, ama bundan hiç bahsedilmedi)

DBMS'nizi belirtmediniz.

Standart SQL'de (ve Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB ve H2 gibi en modern DBMS) şunları belirtebilir NULLS LASTveya NULLS FIRST:

NULLS LASTBunları sonuna kadar sıralamak için kullanın :

select *
from some_table
order by some_column DESC NULLS LAST

16
AFAIK NULLS FIRSTve NULLS LASTSQL'de eklenmiştir: 2003 ama farklı DMBS'lerde standart bir uygulama mevcut değildir. Veritabanı motoruna bağlı olarak, ORDER BY expr some_column DESC NULLS LAST(Oracle), ORDER BY ISNULL(some_column, 1), some_column ASC(MSSQL) veya ORDER BY ISNULL(some_column), some_column ASC(MySQL ile farklı bir ISNULL () uygulaması) kullanın.
SaschaM78

3
@ SaschaM78: NULL'ların varsayılan sıralaması DBMS'ye bağlıdır. Bazıları onları sonunda, bazıları başında. Bazı yaklaşık zahmet etmeyin ASC/ DESCbazı yapmak nulls ile. Bunu sağlamak için tek yol Yani kullanmaktır NULL FIRST/LAST eğer DBMS bunu destekler. Bu konuda ne istediğini belgeliyor . isnull()Veya diğer işlevlerin kullanımı eksik destek için bir NULLS FIRST/LASTçözümdür (Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB ve H2 tarafından desteklenmektedir)
a_horse_with_no_name 23:13

Mükemmel haklısın, sadece standart (henüz) takip etmeyen ya da Oracle gibi exprNULLS FIRST / LAST kullanırken anahtar kelime gerektiren kendi uzmanlık var oldukça bazı DBMS olduğu gerçeğini eklemek istedim . Ve veritabanı göstergesinden tipe değişen ilk / son null'lar sayesinde, bunu bilmiyordum!
SaschaM78

2
Bu umut verici görünüyor, ama ne yazık ki, denedim ve NULLS LASTMySQL veritabanımda çalışmadı.
2017'de

1
@AdmiralAdama: Her zaman Postgres'e yükseltebilirsiniz
a_horse_with_no_name


14
order by coalesce(date-time-field,large date in future)

10
Bu genellikle işe yarar olsa da, bu cevabın birkaç sorunu olduğu unutulmamalıdır: gelecekte büyük tarih gerçek verilerle çarpışabilir veya daha az olabilir ve bu da kusurlu bir sıralama ile sonuçlanabilir. Ayrıca, kendi kendini belgelemeyen bir "sihirli sayı" çözümüdür.
RedFilter

Söz konusu sütunu başka bir tarih sütunuyla karşılaştırmanız gerektiğinde, bu @RedFilter yanıtına mükemmel bir alternatiftir. Bunu sendika kıdem listesi için kullanıyorum. Çalışanın Kalifiye bir tarihi varsa (geçersizdir), bu tarih balonları en üste kaydedilir, aksi takdirde HireDate kullanın. ORDER BY ISNULL (QualifiedDate, '1-1-2099'), HireDate, LastName, vb. Kullanılarak Qualified tarihi HiredDate tarihiyle çakışmaz ve doğru yaşlanma listesi oluşturulur.
Alan Fisher

14

Yerleşik işlevi null olup olmadığını kontrol etmek için aşağıdaki gibi kullanabilirsiniz. Test ediyorum ve iyi çalışıyor.

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


Mssql ile çalışmak için tarihler için ISNULL işlevine, örneğin ISNULL'a (MyDate, '2100-01-01') çok uzak bir tarih koymak yararlı buldum
Emi-C

MySQL'de çok fazla parametre geçirdiğimi söylüyor. Bunu yaparak ayrıştırmak için aldım ISNULL(MyDate) DESC, MyDate ASC, ama doğru sırada sıralanmadı.
AmiralThrawn

12

Motorunuz buna izin veriyorsa ORDER BY x IS NULL, xveya ORDER BY x NULLS LASTkullanıyorsa. Ancak, bunlar yardımcı olmazsa:

Sayısal bir türe göre sıralıyorsanız, bunu yapabilirsiniz: (Şemayı başka bir yanıttan ödünç almak .)

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

sonuç gösterme en son nulls ile DepartmentId göre sıralanmış

Null olmayan herhangi bir sayı 0 olur ve null değeri 1 olur ve bu null değerini en son sıralar.

Bunu dizeler için de yapabilirsiniz:

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

sonuç nulls sonuncusu ile LastName göre sıralanmış

Çünkü 'a'> ''.

Bu, null olabilecek bir int'e zorlayarak ve yukarıdaki ints yöntemini kullanarak tarihlerle bile çalışır:

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

(Şemanın HireDate olduğunu varsayalım.)

Bu yöntemler, veri türü (ve maksimum) değiştiğinde (diğer ISNULL çözümlerinin yaşadığı her iki sorun) her türden "maksimum" değer bulmak veya yönetmek veya sorguları düzeltmek sorununu önler. Ayrıca bir VAKA'dan daha kısadırlar.


Harika çalışıyor! Teşekkür ederim
Vani

8

Sipariş sütununuz sayısal olduğunda (sıralama gibi) onu -1 ile çarpabilir ve ardından azalan sırada olabilirsiniz. Beklediğiniz siparişi koruyacak, ancak NULL değerini koyacaktır.

select *
from table
order by -rank desc

Bu konuda yorum yapmak üzereydi. Stackoverflow.com/a/8174026/1193304
Chris


3

Sıfırlanabilir datetime alanını sıralamadaki hatalara mükemmel çözüm sağladığı için RedFilter'a teşekkürler.

Projem için SQL Server veritabanı kullanıyorum.

Datetime null değerini '1' olarak değiştirmek, datetime veri türü sütunu için sıralama sorununu çözer. Ancak, datetime veri türünden başka bir sütuna sahipsek, işlenemez.

Bir varchar sütun sıralaması işlemek için sütun 'Z' ile başlayan değerleri olmadığını biliyordum 'ZZZZZZZ' kullanmayı denedim. Beklendiği gibi çalıştı.

Aynı satırlarda, sıralamayı beklendiği gibi almak için int ve diğer veri türleri için +1 değerlerini kullandım. Bu da bana gerekli sonuçları verdi.

Ancak, veritabanı motorunun kendisinde şöyle bir şey yapabilen daha kolay bir şey elde etmek her zaman ideal olacaktır:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

A_horse_with_no_name tarafından verilen cevapta belirtildiği gibi.



3

MariaDB kullanıyorsanız, NULL Değerler belgelerinde aşağıdakilerden bahsederler .

Sipariş

NULL değerleri içerebilecek bir alana göre sipariş verdiğinizde, tüm NULL değerlerinin en düşük değere sahip olduğu kabul edilir. Bu yüzden DESC sırasında sipariş vermek NULL'ların en son göründüğünü görecektir. NULL değerlerini en yüksek değerler olarak kabul etmeye zorlamak için, ana alan NULL olduğunda daha yüksek bir değere sahip başka bir sütun eklenebilir. Misal:

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

Önce NULL'lar ile azalan düzen:

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

Tüm NULL değerleri, DISTINCT ve GROUP BY deyimleri için eşdeğer olarak kabul edilir.

Yukarıda NULL değerlerine göre sipariş vermenin iki yolu gösterilmektedir, bunları ASC ve DESC anahtar sözcükleriyle de birleştirebilirsiniz. Örneğin, ilk olarak NULL değerlerini almanın diğer yolu:

SELECT col1 FROM tab ORDER BY ISNULL(col1) DESC, col1;
--                                         ^^^^

2

"Case" kullanarak çözüm evrenseldir, ancak daha sonra indeksleri kullanmayın.

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

Benim durumumda, performansa ihtiyacım vardı.

 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)  

1
Performansla ilgileniyorsanız, kullanmalısınız UNION ALL.
RedFilter


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.