2013-05-10 17 views
8

Rails3 uygulamasında beklenmedik bir postgres sorgu sorununa rastladım. Bir SQL sorgusunda NULL! = Değeri (postgres ve rails3)

ben stackoverflow bu çalıştırın ve internet beyinleri söylemek :)

bu sonuç Beklenen davranış (ve neden ?!) mı yoksa bu bir hata olduğunu ne olduğunu görmek düşündüm? Ben, Siparişler, benim Postgres 9.1.4 veritabanı bir tablo var olduğu göz önüne alındığında

:

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

Ben sorguyu çalıştırdığınızda:

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

=> [3] 

bekliyordum sonucu [1, 3 ]. Açıkça (! = 'Başarı') olan 2 satır vardır.

Neden bu nil! = 'Başarı' burada doğru değil mi? Yapar! = NULL değerleri görmezden gelmek mi? yapmalı mıyım?

NOT: herhangi bir yorum mutluluk duyacağız

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] 

: Aşağıdaki sorguyu kullanarak istenen sonucu üretti.

+0

Neden olduğunu bilmiyorum ama ilk isteğiniz * qb_sync_status * kontrol ederken * durumu * ... – Raindal

+0

aah, çünkü bu örneği kötü kopyalayıp yapıştırdım. düzeltildi, teşekkürler Sparda –

+0

Bu, temeldeki SQL'in çalışması için bir yoldur. NULL değeri, veri seçerken sorunlara neden olabilir, çünkü bilinmeyen bir değeri, yani NULL'u başka herhangi bir değere kıyasla, sonuç her zaman bilinmez ve nihai sonuçlara dahil değildir. – thisfeller

cevap

10

PostgreSQL bir IS DISTINCT FROM karşılaştırma operatörü yoktur:

Elbette ek bir koşul kullanabilirsiniz

Olağan karşılaştırma operatörleri verim boş (simgeleyen "bilinmeyen") doğru değil, ya da yanlış, her iki giriş null olduğunda. Örneğin, 7 <> NULL, 7 = NULL null değerini verir.Bu davranış, uygun olmadığında, IS [ NOT ] DISTINCT FROM teknikleri kullanarak: boş olmayan girişleri için

expression IS DISTINCT FROM expression 
expression IS NOT DISTINCT FROM expression 

, IS DISTINCT FROM<> operatör ile aynıdır. Ancak, her iki girdi de boşsa, false değerini döndürür ve yalnızca bir girdi boşsa true değerini döndürür. Benzer şekilde, IS NOT DISTINCT FROM, null olmayan girişler için = ile aynıdır, ancak her iki girdi de boş olduğunda ve yalnızca bir giriş null olduğunda false döndürür. Dolayısıyla, bu yapılar, null, "bilinmeyen" yerine, normal bir veri değeriymiş gibi etkili davranırlar. Ben de bu göndereceği, yerine kendi map(&:id) daha pluck geçiş

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

Not:

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

Yani bunun söyleyebiliriz: En örnek veri Verilen örnek için

, SQL veritabanına:

s ürününü ayıklamak için istemci tarafı filtreyle birlikte select orders.* ... yerine.
0

Bu, en az bir NULL içeren iki değer arasındaki karşılaştırmanın ne doğru, ne yanlış, ne de bilinmeyen olarak döndüğü SQL standardının bir parçasıdır.

  • http://www-cs-students.stanford.edu/~wlam/compsci/sqlnulls itibaren NULL karıştığı iki değer arasındaki bir boole karşılaştırma doğru ne yanlış, ama SQL'ın üç değerli mantık bilinmeyen ne döndürür. [3] Örneğin, NULL eşittir NULL veya NULL eşittir NULL doğru değil. Bir değerin NULL olup olmadığını test etmek IS NULL veya IS NOT NULL gibi bir ifade gerektirir.
  • Bir SQL sorgusu yalnızca WHERE ifadesi doğru olarak değerlendirilen değerleri ve HAVING yan tümcesi doğru olarak değerlendirilen grupları seçer. NULL'dur

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

    orders.state ise, o zaman karşılaştırmadan doğru veya yanlış dönecektir 'NIL', ile değiştirecektir:

bir çözüm COALESCE kullanmaktır.

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

'isnull()', AFAIK, bir MySQLism. Standart yol, 'order.state boş 'demek. –