Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Result of NULL != value in an SQL query (postgres and rails3)

I ran into a unexpected postgres query issue within my Rails3 app.

I thought I'd run this by stackoverflow and see what the brains of the internet have to say :)

Is this result Expected behaviour (and why?!) or is this a bug?

Given that I have a table, Orders, in my Postgres 9.1.4 database:

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

When I run the query:

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

=> [3]

I was expecting the result [1, 3]. There are clearly 2 rows in which (!= 'success') is satisfied.

Why is it that nil != 'success' is not true here? Does != just ignore NULL values? should it?

NOTE: I produced the desired result by using the following query:

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]

Any comments would be appreciated.

like image 219
Matt Riemer Avatar asked May 10 '13 16:05

Matt Riemer


People also ask

How do you handle NULL values in PostgreSQL?

In PostgreSQL, NULL means no value. In other words, the NULL column does not have any value. It does not equal 0, empty string, or spaces. The NULL value cannot be tested using any equality operator like “=” “!=

IS NULL condition in PostgreSQL?

PostgreSQL IS NOT NULL operator.

IS NOT NULL in Postgres query?

Here is an example of how to use the PostgreSQL IS NOT NULL condition in a SELECT statement: SELECT * FROM employees WHERE first_name IS NOT NULL; This PostgreSQL IS NOT NULL example will return all records from the employees table where the first_name does not contain a null value.

WHAT DOES NOT NULL mean in PostgreSQL?

The not-null constraint in PostgreSQL ensures that a column can not contain any null value. This is a column constraint. No name can be defined to create a not-null constraint. This constraint is placed immediately after the data-type of a column. Any attempt to put NULL values in that column will be rejected.


1 Answers

There is an IS DISTINCT FROM comparison operator in PostgreSQL:

Ordinary comparison operators yield null (signifying "unknown"), not true or false, when either input is null. For example, 7 = NULL yields null, as does 7 <> NULL. When this behavior is not suitable, use the IS [ NOT ] DISTINCT FROM constructs:

expression IS DISTINCT FROM expression
expression IS NOT DISTINCT FROM expression

For non-null inputs, IS DISTINCT FROM is the same as the <> operator. However, if both inputs are null it returns false, and if only one input is null it returns true. Similarly, IS NOT DISTINCT FROM is identical to = for non-null inputs, but it returns true when both inputs are null, and false when only one input is null. Thus, these constructs effectively act as though null were a normal data value, rather than "unknown".

For example, given your sample data:

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

So you could say this:

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

Note that I also switched to pluck rather than your map(&:id), that will send this SQL to the database:

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

rather than select orders.* ... with client-side filter to extract the ids.

like image 143
mu is too short Avatar answered Oct 31 '22 02:10

mu is too short