2013-05-10 49 views
8

我在Rails3應用程序中遇到了意外的postgres查詢問題。NULL!= SQL查詢中的值(postgres和rails3)的結果

我想我會用計算器運行這個,看看互聯網的大腦不得不說:)

是這樣的結果預期的行爲(爲什麼?),或者這是一個錯誤?

假設我有一個表,訂單,在我的Postgres 9.1.4數據庫:

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

當我運行查詢:

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

=> [3] 

我期待的結果[1,3 ]。顯然有2行滿足(!='success')。

爲什麼nil!='success'在這裏不是真的?不!!=只是忽略空值?應該是?

注:我公司生產通過使用下面的查詢所期望的結果:

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] 

任何意見,將不勝感激。

+0

不知道爲什麼,但你的第一個請求是檢查* qb_sync_status *而它應該檢查*狀態* ... – Raindal 2013-05-10 16:10:22

+0

啊,因爲我很好地複製和粘貼這個例子。更正,謝謝Sparda – 2013-05-10 16:19:01

+0

這是底層SQL設計工作的方式。在選擇數據時,NULL值可能會導致問題,因爲當將未知值(即NULL)與任何其他值進行比較時,結果始終未知並且未包含在最終結果中。 – thisfeller 2013-05-10 16:26:26

回答

10

在PostgreSQL裏的IS DISTINCT FROM比較操作:

普通比較運算符產量空(表示「未知」),而不是真正的或假,當任何輸入爲空。例如,7 = NULL產生空,如7 <> NULL。當發生這種情況是不適合的,使用IS [ NOT ] DISTINCT FROM構建體:

expression IS DISTINCT FROM expression 
expression IS NOT DISTINCT FROM expression 

對於非空輸入,IS DISTINCT FROM是一樣的操作者<>。但是,如果兩個輸入都爲空,則返回false,並且如果只有一個輸入爲空,則返回true。同樣,對於非空輸入,IS NOT DISTINCT FROM=相同,但當兩個輸入都爲空時它將返回true,而當只有一個輸入爲空時它將返回false。因此,這些結構有效地表現爲空值是正常的數據值,而不是「未知」。

例如,假設您的樣本數據:

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

所以,你可以這樣說:

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

請注意,我也切換到pluck,而不是你的map(&:id),將發送此SQL到數據庫:

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

而不是select orders.* ...與客戶端過濾器來提取id s。

0

這是SQL標準的一部分,其中涉及至少一個NULL的兩個值之間的比較既不會返回true也不會返回false,但不會返回值。

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

  • 涉及NULL兩個值之間的布爾比較返回非真非假,但在SQL的三值邏輯不明。 [3]例如,NULL既不等於NULL也不等於NULL不等於NULL。測試一個值是否爲NULL需要表達式如IS NULL或IS NOT NULL。
  • SQL查詢只選擇其WHERE表達式計算結果爲true的值以及其HAVING子句的計算結果爲true的組。

一種解決方案是使用COALESCE:

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

如果orders.state爲NULL,它將與 'NIL',然後將比較返回true或false替換它。

當然你也可以使用一個附加條件:

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

'isnull()'是,AFAIK,一個MySQLism。標準的方式是說'orders.state爲null'。 – 2013-11-06 20:40:18