How to write a null safe compare “<=>” in pure SQL?
Question
In Mysql there is a compare operator that is a null safe: <=>. I use this in my Java program when creating prepared statements like this:
String routerAddress = getSomeValue();
String sql = "SELECT * FROM ROUTERS WHERE ROUTER_ADDRESS <=> ? ";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, routerAddress);
Now I would like to switch to the H2 database. How do I write the <=> operator in pure SQL (using for example IS NULL and IS NOT NULL)? I would like use the stmt.setString operation only once. It is okay to write the column name several times.
Related question is Get null == null in SQL. But that answer requires the search value to be written 2 times (that is: 2 question marks in my PreparedStatement)!?
Reference: http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#operator_equal-to
Solution
Related question is Get null == null in SQL. But that answer requires the search value to be written 2 times (that is: 2 question marks in my PreparedStatement)!?
The second-ranked and subsequent answers give a method to do this without binding the search value twice:
SELECT * FROM ROUTERS
WHERE coalesce(ROUTER_ADDRESS, '') = coalesce( ?, '');
Note that this requires a dummy value that can never be valid column value (that's "out of band"); I'm using the empty string. If you don't have any such value, you'll have to put up with binding the value twice:
SELECT * FROM ROUTERS
WHERE ROUTER_ADDRESS = ? or (ROUTER_ADDRESS is null and ? is null);
OTHER TIPS
The standard NULL-safe equality operators in SQL are IS DISTINCT FROM
and IS NOT DISTINCT FROM
.
In SQL, NULL is not equal to itself. So you can either:
1 - Replace it with a dummy value and compare those, as in:
SELECT * FROM ROUTERS WHERE ISNULL(ROUTER_ADDRESS,'xxx') <=> ISNULL(?,'xxx')
or
2 - Replace it with a more elaborate logical test, as in:
SELECT *
FROM ROUTERS
WHERE (
(ROUTER_ADDRESS IS NULL AND ? IS NOT NULL)
OR
(ROUTER_ADDRESS IS NOT NULL AND ? IS NULL)
OR
(ROUTER_ADDRESS IS NOT NULL AND ? IS NOT NULL AND ROUTER_ADDRESS <> ?
)
If you want ROUTERS where ROUTER_ADDRESS is null when ? is null then possibly this could work:
SELECT *
FROM ROUTERS
WHERE ROUTER_ADDRESS = (case when ROUTER_ADDRESS is null and ? is null then null
else ? end)