SQL làm thế nào để làm cho các giá trị null xuất hiện sau cùng khi sắp xếp tăng dần


297

Tôi có một bảng SQL với trường datetime. Trường trong câu hỏi có thể là null. Tôi có một truy vấn và tôi muốn các kết quả được sắp xếp tăng dần theo trường datetime, tuy nhiên tôi muốn các hàng trong đó trường datetime là null ở cuối danh sách, không phải ở đầu danh sách.

Có một cách đơn giản để thực hiện điều đó?



Câu trả lời:


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

2
Tuy nhiên, lưu ý rằng nếu bạn đặt một chỉ mục trên cột sắp xếp để cải thiện hiệu suất (*), thì phương pháp này sẽ phần nào làm phức tạp kế hoạch truy vấn và mất phần lớn lợi ích hiệu suất. * - các chỉ mục cung cấp dữ liệu được đặt trước, do đó tránh sắp xếp theo thực thi truy vấn. Bạn nên lọc các bản ghi NULL nếu có thể để tránh vấn đề này hoàn toàn.
redcalx

2
Câu trả lời hay cũng được đưa ra ở đây với tất cả các cách có thể với ưu điểm và nhược điểm nickstips.wordpress.com/2010/09/30/NH
sudhAnsu63

40
order by case when MyDate is null then 1 else 0 endlà một cách nói rất dàiORDER BY MyDate IS NULL
Martin

5
@Martin Lưu ý câu hỏi này không được gắn thẻ mysql. Tôi đã cung cấp một giải pháp tổng quát - có nhiều cách khác nhau để làm điều tương tự trên các dbs khác nhau.
RedFilter

1
@KyleDelaney Bởi vì order by 0được hiểu là một chỉ mục cột và các chỉ mục cột là dựa trên 1. Để sắp xếp truy vấn theo cột thứ 3, bạn có thể nói order by 3(đó là một ý tưởng tồi cho các truy vấn sản xuất), nhưng rất tiện dụng (như hiện tại *) khi thử nghiệm.
RedFilter

159

(Một chút "muộn", nhưng điều này đã không được đề cập ở tất cả)

Bạn đã không chỉ định DBMS của bạn.

Trong SQL tiêu chuẩn (và hầu hết các DBMS hiện đại như Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB và H2), bạn có thể chỉ định NULLS LASThoặc NULLS FIRST:

Sử dụng NULLS LASTđể sắp xếp chúng đến cuối:

select *
from some_table
order by some_column DESC NULLS LAST

16
AFAIK NULLS FIRSTNULLS LASTđã được thêm vào trong SQL: 2003 nhưng không có triển khai tiêu chuẩn có sẵn trong các DMBS khác nhau '. Tùy thuộc vào công cụ cơ sở dữ liệu, sử dụng ORDER BY expr some_column DESC NULLS LAST(Oracle), ORDER BY ISNULL(some_column, 1), some_column ASC(MSSQL) hoặc ORDER BY ISNULL(some_column), some_column ASC(MySQL khi thực hiện ISNULL () khác nhau).
SaschaM78

3
@ SaschaM78: việc sắp xếp mặc định của NULL là phụ thuộc DBMS. Một số sắp xếp chúng ở cuối, một số ở đầu. Một số không bận tâm về ASC/ DESCvới null một số làm. Vì vậy, cách duy nhất để đảm bảo điều này, là sử dụng NULL FIRST/LAST nếu DBMS hỗ trợ nó. Tại nó tài liệu những gì bạn dự định. Việc sử dụng isnull()hoặc các chức năng khác là một cách giải quyết cho sự hỗ trợ còn thiếu cho NULLS FIRST/LAST(được hỗ trợ bởi Oracle, PostgreQuery, DB2, Firebird, Apache Derby, HSQLDB và H2)
a_horse_with_no_name

Bạn hoàn toàn đúng, tôi chỉ muốn thêm một thực tế là có khá nhiều DBMS xung quanh không tuân theo tiêu chuẩn (chưa) hoặc có các chuyên môn của họ như Oracle yêu cầu exprtừ khóa khi sử dụng NULLS FIRST / LAST. Và cảm ơn về các null được hiển thị đầu tiên / cuối cùng khác nhau từ loại cơ sở dữ liệu đến loại, không biết điều đó!
SaschaM78

2
Điều này có vẻ đầy hứa hẹn, nhưng thật đáng buồn, tôi đã thử nó và NULLS LASTkhông hoạt động trong cơ sở dữ liệu MySQL của tôi.
Đô đốcThrawn

1
@AdmirusAdama: bạn luôn có thể nâng cấp lên Postgres
a_horse_with_no_name

35

Tôi cũng chỉ tình cờ phát hiện ra điều này và những điều sau đây dường như thực hiện mánh khóe cho tôi, trên MySQL và PostgreQuery:

ORDER BY date IS NULL, date DESC

như được tìm thấy tại https://stackoverflow.com/a/7055259/496209


Ngoại hình này hứa hẹn, nhưng buồn thay, tôi đã thử nó và IS NULLIS NOT NULLkhông làm việc trong cơ sở dữ liệu MySQL của tôi.
Đô đốcThrawn

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

10
Mặc dù điều này thường sẽ hoạt động, nhưng cần lưu ý rằng câu trả lời này có một số vấn đề: ngày lớn trong tương lai có thể va chạm hoặc ít hơn dữ liệu thực tế, dẫn đến một loại không hoàn hảo. Ngoài ra, đó là một giải pháp "số ma thuật" không phải là tài liệu tự.
RedFilter

Điều này xảy ra là một thay thế tuyệt vời cho câu trả lời @RedFilter khi bạn cần so sánh cột được đề cập với cột ngày khác. Tôi sử dụng này cho danh sách thâm niên của công đoàn. Nếu nhân viên có một Ngày đủ điều kiện (không thể thực hiện được), ngày đó sẽ ghi lại bong bóng vào đầu, nếu không thì sử dụng HireDate. Sử dụng ĐẶT HÀNG B ISNG ISNULL (QualifiedDate, '1-1-2099'), HireDate, LastName, v.v ... làm cho Ngày đủ điều kiện không xung đột với ngày HiredDate và danh sách lão hóa chính xác được tạo ra.
Alan Fisher

14

Bạn có thể sử dụng chức năng tích hợp để kiểm tra null hoặc không null, như dưới đây. Tôi kiểm tra nó và nó hoạt động tốt.

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


Đối với các ngày để làm việc với mssql, tôi thấy hữu ích khi đặt một ngày xa trong chức năng ISNULL, tức là ISNULL (MyDate, '2100-01-01')
Emi-C

Trong MySQL, nó nói rằng tôi đang truyền quá nhiều tham số. Tôi đã làm điều này để phân tích bằng cách làm ISNULL(MyDate) DESC, MyDate ASC, nhưng nó không sắp xếp theo đúng thứ tự.
Đô đốcThrawn

12

Nếu động cơ của bạn cho phép ORDER BY x IS NULL, xhoặc ORDER BY x NULLS LASTsử dụng đó. Nhưng nếu nó không có thể giúp:

Nếu bạn sắp xếp theo loại số, bạn có thể thực hiện việc này: (Mượn lược đồ từ câu trả lời khác .)

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

kết quả hiển thị được sắp xếp bởi DepartmentId với null cuối cùng

Bất kỳ số không null nào cũng trở thành 0 và null trở thành 1, sắp xếp các giá trị null cuối cùng.

Bạn cũng có thể làm điều này cho chuỗi:

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

kết quả hiển thị được sắp xếp theo LastName với null cuối cùng

'a'> ''.

Điều này thậm chí hoạt động với ngày bằng cách ép buộc vào một int nullable và sử dụng phương thức cho ints ở trên:

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

(Hãy giả vờ lược đồ có HireDate.)

Các phương pháp này tránh vấn đề phải đưa ra hoặc quản lý giá trị "tối đa" của mọi loại hoặc sửa các truy vấn nếu loại dữ liệu (và tối đa) thay đổi (cả hai vấn đề mà các giải pháp ISNULL khác mắc phải). Thêm vào đó, chúng ngắn hơn nhiều so với CASE.


Hoạt động tuyệt vời! Cảm ơn bạn
Vani

8

Khi cột đơn hàng của bạn là số (như thứ hạng), bạn có thể nhân nó với -1 và sau đó thứ tự giảm dần. Nó sẽ giữ thứ tự bạn đang thực hiện nhưng đặt NULL sau cùng.

select *
from table
order by -rank desc

Chỉ là về nhận xét này. Đã học nó từ stackoverflow.com/a/8174026/1193304 và thật tuyệt
Chris


3

Cảm ơn RedFilter đã cung cấp giải pháp tuyệt vời cho vấn đề lỗi của việc sắp xếp trường datetime nullable.

Tôi đang sử dụng cơ sở dữ liệu SQL Server cho dự án của mình.

Thay đổi giá trị null datetime thành '1' sẽ giải quyết vấn đề sắp xếp cho cột kiểu dữ liệu datetime. Tuy nhiên nếu chúng ta có cột khác với kiểu dữ liệu datetime thì nó không thể xử lý được.

Để xử lý một loại sắp xếp cột varchar, tôi đã thử sử dụng 'ZZZZZZZ' vì tôi biết cột không có giá trị bắt đầu bằng 'Z'. Nó làm việc như mong đợi.

Trên cùng một dòng, tôi đã sử dụng các giá trị tối đa +1 cho int và các loại dữ liệu khác để có được sắp xếp như mong đợi. Điều này cũng cho tôi kết quả theo yêu cầu.

Tuy nhiên, sẽ thật lý tưởng khi có được thứ gì đó dễ dàng hơn trong chính công cụ cơ sở dữ liệu có thể làm một cái gì đó như:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

Như đã đề cập trong câu trả lời được cung cấp bởi a_horse_with_no_name.



3

Nếu bạn đang sử dụng MariaDB, họ sẽ đề cập đến những điều sau đây trong tài liệu Giá trị NULL .

Đặt hàng

Khi bạn đặt hàng theo trường có thể chứa giá trị NULL, mọi NULL đều được coi là có giá trị thấp nhất. Vì vậy, đặt hàng theo thứ tự DESC sẽ thấy các NULL xuất hiện lần cuối. Để buộc các NULL được coi là giá trị cao nhất, người ta có thể thêm một cột khác có giá trị cao hơn khi trường chính là NULL. Thí dụ:

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

Thứ tự giảm dần, với NULL đầu tiên:

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

Tất cả các giá trị NULL cũng được coi là tương đương cho các mục đích của mệnh đề DISTINCT và GROUP BY.

Ở trên cho thấy hai cách để sắp xếp theo giá trị NULL, bạn cũng có thể kết hợp những cách này với các từ khóa ASC và DESC. Ví dụ, cách khác để nhận các giá trị NULL trước tiên sẽ là:

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

2

Giải pháp sử dụng "trường hợp" là phổ biến, nhưng sau đó không sử dụng các chỉ mục.

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

Trong trường hợp của tôi, tôi cần hiệu suất.

 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
Nếu bạn quan tâm đến hiệu suất, bạn nên sử dụng UNION ALL.
RedFilter


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.