SQL Server ORDER THEO ngày tháng và giá trị rỗng cuối cùng


82

Tôi đang cố gắng đặt hàng theo ngày. Tôi muốn những ngày gần đây nhất đến trước. Điều đó đủ dễ dàng, nhưng có nhiều bản ghi trống và những bản ghi đó xuất hiện trước bất kỳ bản ghi nào có ngày tháng.

Tôi đã thử một số cách nhưng không thành công:

ORDER BY ISNULL(Next_Contact_Date, 0)

ORDER BY ISNULL(Next_Contact_Date, 999999999)

ORDER BY coalesce(Next_Contact_Date, 99/99/9999)

Làm cách nào để tôi có thể đặt hàng theo ngày và đặt hàng null cuối cùng? Kiểu dữ liệu là smalldatetime.


Thứ tự sắp xếp có cần Tăng dần, nhưng có null ở cuối không? Và bạn sẽ có ngày trong tương lai trong bảng của bạn?
AllenG

@AllenG, vâng, từ quá khứ đến tương lai với quá khứ trước, v.v. Vì vậy, yeah, tăng dần. Vâng, những ngày trong tương lai là những gì hầu hết trong số họ sẽ là.
UpHelix

Câu trả lời:


112

smalldatetime có phạm vi đến ngày 6 tháng 6 năm 2079 nên bạn có thể sử dụng

ORDER BY ISNULL(Next_Contact_Date, '2079-06-05T23:59:00')

Nếu không có hồ sơ hợp pháp sẽ có ngày đó.

Nếu đây không phải là một giả định, bạn muốn dựa vào một tùy chọn mạnh mẽ hơn là sắp xếp trên hai cột.

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

Tuy nhiên, cả hai gợi ý trên đều không thể sử dụng một chỉ mục để tránh sắp xếp và đưa ra các kế hoạch giống nhau.

nhập mô tả hình ảnh ở đây

Một khả năng khác nếu một chỉ mục như vậy tồn tại là

SELECT 1 AS Grp, Next_Contact_Date 
FROM T 
WHERE Next_Contact_Date IS NOT NULL
UNION ALL
SELECT 2 AS Grp, Next_Contact_Date 
FROM T 
WHERE Next_Contact_Date IS NULL
ORDER BY Grp, Next_Contact_Date

Kế hoạch


Thủ thuật này cũng có thể được áp dụng cho VARCHARcác trường (ví dụ ORDER BY ISNULL(my_varchar, 'ZZZZZZ')) và cực kỳ hữu ích, đặc biệt là để nhận đơn đặt hàng theo một cách nhất định khi sử dụng GROUP BY . . . GROUPING SETS. Cảm ơn vì đã đăng bài này.
sparc_spread

Tại sao chúng ta không thể sử dụng order by desc để đặt null ở dưới cùng? ngoài ra, tại sao chúng tôi ánh xạ null thành 1?
MasterJoe

35

Theo Itzik Ben-Gan, tác giả của T-SQL Fundamentals for MS SQL Server 2012 , "Theo mặc định, SQL Server sắp xếp các dấu NULL trước các giá trị không phải NULL . Để có dấu NULL để sắp xếp cuối cùng, bạn có thể sử dụng biểu thức CASE trả về 1 khi cột " Next_Contact_DateNULL " và 0 khi nó không phải NULL . Các dấu không NULL nhận lại 0 từ biểu thức; do đó, chúng sắp xếp trước các dấu NULL (nhận 1). Biểu thức CASE này được sử dụng làm dấu hiệu đầu tiên cột sắp xếp. " The Next_Contact_Datecột "phải được chỉ định là cột sắp xếp thứ hai. Bằng cách này, các dấu không phải NULL sắp xếp chính xác giữa chúng." Đây là truy vấn giải pháp cho ví dụ của bạn cho MS SQL Server 2012 (và SQL Server 2014):

ORDER BY 
   CASE 
        WHEN Next_Contact_Date IS NULL THEN 1
        ELSE 0
   END, Next_Contact_Date;

Mã tương đương sử dụng cú pháp IIF:

ORDER BY 
   IIF(Next_Contact_Date IS NULL, 1, 0),
   Next_Contact_Date;

Ngoài ra, để thêm vào câu trả lời, nếu bạn chuyển 1 và 0 của IIF xung quanh các giá trị null sẽ lên trên cùng. Điều này cũng hoạt động nếu bạn muốn có một bộ tài liệu duy nhất bằng cách đặt chúng lên đầu bảng.
Franco Pettigrosso

3

Nếu SQL của bạn không hỗ trợ NULLS FIRSThoặc NULLS LAST, cách đơn giản nhất để làm điều này là sử dụng value IS NULLbiểu thức:

ORDER BY Next_Contact_Date IS NULL, Next_Contact_Date

đặt null ở cuối ( NULLS LAST) hoặc

ORDER BY Next_Contact_Date IS NOT NULL, Next_Contact_Date

để đặt nulls ở phía trước. Điều này không yêu cầu biết loại cột và dễ đọc hơn CASEbiểu thức.

CHỈNH SỬA: Than ôi, trong khi điều này hoạt động trong các triển khai SQL khác như PostgreSQL và MySQL, nó không hoạt động trong MS SQL Server. Tôi không có SQL Server để kiểm tra và dựa vào tài liệu của Microsoft và kiểm tra với các triển khai SQL khác. Theo Microsoft, value IS NULL là một biểu thức có thể được sử dụng giống như bất kỳ biểu thức nào khác. Và ORDER BY phải nhận biểu thức giống như bất kỳ câu lệnh nào khác nhận biểu thức. Nhưng nó không thực sự hoạt động.

Do đó, giải pháp tốt nhất cho SQL Server dường như là CASEbiểu thức.


7
Đây không phải là cú pháp SQL Server hợp lệ
Martin Smith

3
Xin lỗi vì điều đó. Nó phải hợp lệ theo tài liệu của Microsoft và hoạt động trong các SQL khác, nhưng MS thực sự không cho phép nó.
Vroo

hiệu suất khôn ngoan này nghe có vẻ khủng khiếp của bạn đang làm 2 tiêu chí phân loại
ColacX

Trong tài liệu của Microsoft mà bạn đã liên kết, tôi đọc rằng giá trị IS NULL không phải là một biểu thức , mà là một vị từ . Nó không giống nhau.
BertuPG

1
Theo Microsoft, một vị từ là một biểu thức. Đó thực sự là ba từ đầu tiên tại docs.microsoft.com/en-us/sql/t-sql/queries/predicates
Vroo

3
order by -cast([Next_Contact_Date] as bigint) desc

ném ra một lỗi nếu Next_Contact_Datelà nullExplicit conversion from data type date to bigint is not allowed.
Nerdroid

2

Hơi muộn nhưng có lẽ ai đó thấy hữu ích.

Đối với tôi, ISNULL nằm ngoài câu hỏi do quá trình quét bảng. UNION ALL sẽ cần tôi lặp lại một truy vấn phức tạp và do tôi chỉ chọn TOP X nên nó sẽ không hiệu quả lắm.

Nếu bạn có thể thay đổi thiết kế bảng, bạn có thể:

  1. Thêm một trường khác, chỉ để sắp xếp, chẳng hạn như Next_Contact_Date_Sort.

  2. Tạo trình kích hoạt điền vào trường đó một giá trị lớn (hoặc nhỏ), tùy thuộc vào những gì bạn cần:

    CREATE TRIGGER FILL_SORTABLE_DATE ON YOUR_TABLE AFTER INSERT,UPDATE AS 
    BEGIN
        SET NOCOUNT ON;
        IF (update(Next_Contact_Date)) BEGIN
        UPDATE YOUR_TABLE SET Next_Contact_Date_Sort=IIF(YOUR_TABLE.Next_Contact_Date IS NULL, 99/99/9999, YOUR_TABLE.Next_Contact_Date_Sort) FROM inserted i WHERE YOUR_TABLE.key1=i.key1 AND YOUR_TABLE.key2=i.key2
        END
    END
    

2

Sử dụng mô tả và nhân với -1 nếu cần. Ví dụ cho thứ tự int tăng dần với nulls cuối cùng:

select * 
from
(select null v union all select 1 v union all select 2 v) t
order by -t.v desc

Đừng nghĩ rằng điều này sẽ hiệu quả đối với các biến như ngày tháng ..
Charlotte Deng

1

Tôi biết điều này là cũ nhưng đây là những gì đã làm việc cho tôi

Order by Isnull(Date,'12/31/9999')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.