2013-05-10 36 views
8

Tôi gặp phải vấn đề truy vấn postgres không mong muốn trong ứng dụng Rails3 của tôi.Kết quả của NULL! = Giá trị trong một truy vấn SQL (postgres và rails3)

tôi nghĩ rằng tôi muốn chạy này bằng cách stackoverflow và xem những gì bộ não của internet phải nói :)

là kết quả hành vi này dự kiến ​​(và tại sao ?!) hay đây là lỗi?

Cho rằng tôi có một bảng, Đơn hàng, trong Postgres của tôi 9.1.4 cơ sở dữ liệu:

id  state 
=====  ====== 
1      <-- nil (default value) 
2   'success' 
3   'failure' 

Khi tôi chạy truy vấn:

Order.where('orders.state != ?', 'success').map { |order| order.id } 
Order Load (3.8ms) SELECT "orders".* FROM "orders" WHERE (orders.state != 'success') 

=> [3] 

Tôi đã chờ đợi kết quả [1, 3 ]. Có 2 hàng rõ ràng trong đó (! = 'Success') được thỏa mãn.

Tại sao nil! = 'Success' không đúng ở đây? Có! = Chỉ bỏ qua các giá trị NULL? phải không?

Chú ý: Tôi tạo ra kết quả mong muốn bằng cách sử dụng các truy vấn sau đây:

Order.where('orders.state IS NULL OR orders.state != ?', 'success').map { |order| order.id } 
Order Load (2.3ms) SELECT "orders".* FROM "orders" WHERE (orders.state IS NULL OR orders.state != 'success') 

=> [1, 3] 

Bất kỳ ý kiến ​​sẽ được đánh giá.

+0

Không biết tại sao nhưng yêu cầu đầu tiên của bạn là kiểm tra * qb_sync_status * trong khi nó nên kiểm tra * state * ... – Raindal

+0

aah, vì tôi đã sao chép và dán ít ví dụ này. sửa chữa, cảm ơn Sparda –

+0

Đây là cách mà SQL cơ bản được thiết kế để hoạt động. Giá trị NULL có thể gây ra vấn đề khi chọn dữ liệu vì khi so sánh giá trị không xác định, tức là NULL, với bất kỳ giá trị nào khác, kết quả luôn luôn không xác định và không được bao gồm trong kết quả cuối cùng. – thisfeller

Trả lời

10

Có một nhà điều hành IS DISTINCT FROM so sánh trong PostgreSQL:

Ordinary toán tử so sánh năng suất null (nghĩa "không rõ"), không đúng sự thật hoặc sai, khi một trong hai đầu vào là null. Ví dụ: 7 = NULL sản lượng không, cũng như 7 <> NULL.Khi hành vi này là không phù hợp, sử dụng cấu trúc IS [ NOT ] DISTINCT FROM:

expression IS DISTINCT FROM expression 
expression IS NOT DISTINCT FROM expression 

Đối với đầu vào không null, IS DISTINCT FROM cũng giống như các nhà điều hành <>. Tuy nhiên, nếu cả hai đầu vào là null thì nó trả về false, và nếu chỉ có một đầu vào là null thì nó trả về true. Tương tự, IS NOT DISTINCT FROM giống hệt với = cho đầu vào không null, nhưng nó trả về true khi cả hai đầu vào là null và false khi chỉ có một đầu vào là null. Do đó, các cấu trúc này hoạt động hiệu quả như thể null là một giá trị dữ liệu bình thường, chứ không phải là "không xác định".

Ví dụ, với dữ liệu mẫu của bạn:

=> select * from orders where state is distinct from 'success'; 
id | state 
----+--------- 
    1 | 
    3 | failure 
(2 rows) 

Vì vậy, bạn có thể nói điều này:

Order.where('orders.state is distinct from ?', 'success').pluck(:id) 

Lưu ý rằng tôi cũng chuyển sang pluck hơn map(&:id) của bạn, mà sẽ gửi thông điệp này SQL vào cơ sở dữ liệu:

select id from orders where orders.state is distinct from 'success' 

thay vì select orders.* ... với bộ lọc phía máy khách để trích xuất các id s.

0

Đây là một phần của tiêu chuẩn SQL, khi so sánh giữa hai giá trị liên quan đến ít nhất một giá trị NULL không đúng, cũng không phải là sai, nhưng không xác định.

Từ http://www-cs-students.stanford.edu/~wlam/compsci/sqlnulls

  • Một so sánh boolean giữa hai giá trị liên quan đến một NULL trả không đúng cũng không sai, nhưng chưa rõ là trong logic ba giá trị của SQL. [3] Ví dụ, không phải NULL bằng NULL và NULL không bằng NULL là đúng. Kiểm tra xem một giá trị là NULL đòi hỏi một biểu thức như IS NULL hoặc IS NOT NULL.
  • Truy vấn SQL chỉ chọn các giá trị có biểu thức WHERE đánh giá là đúng và các nhóm có mệnh đề HAVING đánh giá là đúng.

Một giải pháp là sử dụng liên hiệp:

Order.where('COALESCE(orders.state,"NIL") != ?', 'success').map(&:id) 

Nếu orders.state là NULL, nó sẽ thay thế nó với 'NIL', sau đó sẽ trở lại đúng hay sai từ việc so sánh.

Bạn có thể sử dụng tất nhiên một điều kiện bổ sung:

Order.where('orders.state is null OR orders.state != ?', 'success').map(&:id) 
+2

'isnull()' là, AFAIK, một chủ nghĩa MySQL. Cách tiêu chuẩn là để nói 'orders.state là null'. –

Các vấn đề liên quan