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.
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 “=” “!=
PostgreSQL IS NOT NULL operator.
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.
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.
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 does7 <> NULL
. When this behavior is not suitable, use theIS [ 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 id
s.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With