Coalesce vs Case
COALESCE()
is literally shorthand for a CASE
statement, they will perform identically.
However, as podiluska mentioned, ISNULL()
can be occasionally faster than a CASE
statement, but it's likely to be a miniscule increase as these functions are very unlikely to bottleneck your procedure.
Read here more about the performance differences.
COALESCE or CASE more efficient and/or standard
COALESCE
is essentially a shorthanded CASE
statement.
Both are exactly the same.
There is also ISNULL
in SQL Server (differs in other DBMSs), but that's actually a non-standard feature and is actually more limited that COALESCE
.
Difference between COALESCE and CASE IS NOT NULL
Under most circumstances, the two are identical. I think the standard defines COALESCE(X, Y)
as:
(CASE WHEN X IS NOT NULL THEN X ELSE Y END)
Under most circumstances, this does exactly what you expect.
There is one difference. One interpretation of the standard is the X
is evaluated twice when the value is not NULL
. This makes no difference under most circumstances (in most cases, the value would be cached anyway).
Postgres does not do this though. It implements a more reasonable interpretation of the standard. In other words, the two are not exactly identical in Postgres, because Postgres is smart enough to evaluate the first expression once, whether it is NULL
or not.
You can see the effect if you have a volatile function (one whose value changes). In Postgres, the following returns "x" and "y" about the same number of times:
select v.x, coalesce(case when random() > 0.5 then 'x' end, 'y')
from (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) v(x);
Equivalent code in SQL Server returns "y" half the time and "x" and NULL
a quarter of the time each -- because SQL Server treats them the two constructs as exactly equivalent and evaluates the first argument twice under some circumstances.
You can see this in the db<>fiddles here and here.
However, SQL
coalesce and a case statement - explanation?
Without context it's difficult to give a truly helpful answer.
At first glance it looks as though it could be rewritten much more simply from this:
WHERE COALESCE(@field, -1) = CASE @field WHEN 1 THEN 0 ELSE -1 END
to this:
WHERE COALESCE(@field, -1) = -1
If that is true then basically you are saying that if the field is null or the field equals -1 then the condition is true otherwise it's false.
Here are some tests to try to prove this:
-- Original
DECLARE @field INT
SELECT 1 WHERE COALESCE(@field, -1) = CASE @field WHEN 1 THEN 0 ELSE -1 END
SET @field = -1
SELECT 1 WHERE COALESCE(@field, -1) = CASE @field WHEN 1 THEN 0 ELSE -1 END
SET @field = 0
SELECT 1 WHERE COALESCE(@field, -1) = CASE @field WHEN 1 THEN 0 ELSE -1 END
SET @field = 1
SELECT 1 WHERE COALESCE(@field, -1) = CASE @field WHEN 1 THEN 0 ELSE -1 END
SET @field = 2
SELECT 1 WHERE COALESCE(@field, -1) = CASE @field WHEN 1 THEN 0 ELSE -1 END
SET @field = 3
SELECT 1 WHERE COALESCE(@field, -1) = CASE @field WHEN 1 THEN 0 ELSE -1 END
--Rewritten
DECLARE @field INT
SELECT 1 WHERE COALESCE(@field, -1) = -1
SET @field = -1
SELECT 1 WHERE COALESCE(@field, -1) = -1
SET @field = 0
SELECT 1 WHERE COALESCE(@field, -1) = -1
SET @field = 1
SELECT 1 WHERE COALESCE(@field, -1) = -1
SET @field = 2
SELECT 1 WHERE COALESCE(@field, -1) = -1
SET @field = 3
SELECT 1 WHERE COALESCE(@field, -1) = -1
Both sets of queries in this test give the same results, but as I said without context and realistic test data it's difficult to know if there was a reason why the query was written in the way that it originally was.
Here is another example from a different perspective, using a LEFT JOIN:
DECLARE @MainTable AS TABLE(ident INT)
DECLARE @PossibleNullTable AS TABLE(mainIdent INT, field INT)
INSERT INTO @MainTable(ident) VALUES(1)
INSERT INTO @MainTable(ident) VALUES(2)
INSERT INTO @MainTable(ident) VALUES(3)
INSERT INTO @MainTable(ident) VALUES(4)
INSERT INTO @MainTable(ident) VALUES(5)
INSERT INTO @PossibleNullTable(mainIdent, field) VALUES(1,-1)
INSERT INTO @PossibleNullTable(mainIdent, field) VALUES(1,1)
INSERT INTO @PossibleNullTable(mainIdent, field) VALUES(1,0)
INSERT INTO @PossibleNullTable(mainIdent, field) VALUES(2,0)
INSERT INTO @PossibleNullTable(mainIdent, field) VALUES(3,1)
INSERT INTO @PossibleNullTable(mainIdent, field) VALUES(5,-1)
--Original
SELECT *
FROM @MainTable mt
LEFT JOIN @PossibleNullTable pnt
ON mt.ident = pnt.mainIdent
WHERE COALESCE(field, -1) = CASE field WHEN 1 THEN 0 ELSE -1 END
--Original Result
ident mainIdent field
1 1 -1
4 NULL NULL
5 5 -1
--Rewritten
SELECT *
FROM @MainTable mt
LEFT JOIN @PossibleNullTable pnt
ON mt.ident = pnt.mainIdent
WHERE COALESCE(field, -1) = -1
--Rewritten Result
ident mainIdent field
1 1 -1
4 NULL NULL
5 5 -1
Again both queries in this test give the same results.
Coalesce different with case
Your query
with the first and second will reproduce the same result, But you are wrong understanding the Coalesce
concept.
Definition in Documentation Postgresql
The COALESCE function returns the first of its arguments that is not
null. Null is returned only if all arguments are null.
So it means it will return the first argument that is not null
, it is not like case
statement with condition like true
or false
Let's try with example :
select coalesce(null, 1)
It will return 1
like the query you show, or
select coalesce(null, null, 1)
It will return 1
too even 1
in the arg_3
and how about there are 2 value not null
?
select coalesce(null, 1, 2)
It will return 1
. Why? Like in the documentation said "returns the first of its arguments that is not null" so when there is 2 value not null
the first argument have not null
value will get return
You can check this demo and try :
Demo<>Fiddle
Hope it helps
Avoid coalesce() or case when in where clause
The expression
WHERE col = COALESCE(@var,col)
says "if @var is NULL, return TRUE (since col always equals col)" A different approach is:
WHERE @var is NULL or col = @var
If @var is NULL, then the OR condition short-circuits (never needs to do the second part) If @var is NOT NULL, then the second part gets executed.
DB2 Performance CASE vs COALESCE
The performance of case
versus coalesce()
just will not make a difference to a query that is joining three large tables. Such queries are dominated by the time for reading and matching the rows in the table.
By the way, the two are not exactly the same. If you have NULL
values in users.Fname
, then the case
logic would keep them but the coalesce()
logic would fill in the values from the other table.
Your criterion should be clarity of expression. Because you think the case
makes more sense, I would suggest you go with that.
HQL - COALESCE or CASE on LEFT JOIN
Assuming HQL supports coalesce (appears as such when doing a quick search), then you can use coalesce like this:
select coalesce(table1.state, table2.state, 'unknown') as state
from table1
left join table 2
on table2.id = table1.id
The coalesce will grab the first non-null value.
Related Topics
Efficiently Querying a Huge Time Series Table for One Row Every 15 Minutes
Generated Excel from Ssis But Getting Quote in Every Column
How to Add "Weights" to a MySQL Table and Select Random Values According to These
Sql Query for Time In/Out Attendance
Sql to Output Line Number in Results of a Query
How to Do a Count(Distinct) Using Window Functions with a Frame in SQL Server
Merging Two Sqlite Databases Which Both Have Junction Tables
Sql Server 2000 - Query a Table's Foreign Key Relationships
How to Select Avg of Multiple Columns on a Single Row
Is It Faster to Check If Length = 0 Than to Compare It to an Empty String
Create a Trigger to Insert Records from a Table to Another One. Get Inserted Values in a Trigger
Oracle SQL to Sort Version Numbers
Spring Data JPA - Query with The Date Minus 2 Days Not Working
Firstname, Lastname in Sql, Too Complex
Create Unique Index If Not Exists in Postgresql
Replacing Text in a Blob Column