September 27, 2005 at 4:37 am
I have isolated some curious behaviour in SQL Server and wonder what people think of it!
I have a single table with an integer ID column.
Table tbl (ID int NOT NULL) containing 1,2,3,4,5,6,7,8
I have a single view which returns 1 for selected rows in the table.
View vw AS SELECT ID, 1 As Val FROM tbl WHERE ID < 5
In SQL Analyser, ISNULL appears to be returning inconsistent results;
SELECT tbl.ID, Val, ISNULL(Val,0) As [Val2]
FROM tbl LEFT OUTER JOIN vw ON tbl.ID=vw.ID
Returns
ID Val Val2
1 1 1
2 1 1
3 1 1
4 1 1
5 NULL 1
6 NULL 1
7 NULL 1
8 NULL 1
Doesnt seem right to me! What do you think.
September 27, 2005 at 5:14 am
wierd - dont' think I'd expect that, but haven't got access to sql server today to play with
does COALESCE(Val, 0) behave the same?
and do you get the same from ...
SELECT tbl.ID, Val, ISNULL(Val,0) As [Val2]
FROM tbl LEFT OUTER JOIN (select id, val from vw) vw ON tbl.ID=vw.ID
also is your instance on a standalone box or parallel setup, and is it all patched up?
Jon
September 27, 2005 at 5:28 am
Hi Jon
COALESCE(Val,0) returns the expected value of 0 for the missing rows in vw. Thats something Ive learnt today - I didnt know about COALESCE. Thanks.
CASE WHEN Val IS NULL THEN 0 ELSE Val END also works as expected.
SQL Server version is 8.00.760(SP3) which I think is fully patched on a standalone box.
Andy
September 27, 2005 at 6:02 am
Instead of view if the result set is stored in a # table, isnull is working fine.
SELECT ID, 1 As Val into #temp2 FROM tb1 WHERE ID < 5
SELECT tb1.ID, vw.Val, isnull(vw.Val,0) As Val2
FROM tb1 left OUTER JOIN #temp1 vw ON tb1.ID=vw.ID
Rajesh
September 27, 2005 at 6:14 am
Hi Rajesh - Yes, you are right. The first thing I did was to try it on a pair of tables instead of the table and the view and it works as expected.
September 27, 2005 at 6:16 am
Interesting - i didn't know that isnull worked differently from coalesce either, so thanks for that .
I'm just used to using coalesce, and it's quite nice because you can try lots of things - e.g COALESECE(tbl.A, tbl.B, tbl.C, 0)
But it definitely looks like a bug then if that has different behaviour. Only asked if it was a parallel system because they seem (from very small experience with DB2 and SQLServer parallel setups) to have the odd prob or two with ISNULL for some reason.
Jon
September 27, 2005 at 10:31 am
I think because a View is query rewrite and OUTER JOIN default mathematically to a NULL. That is the reason extra care is needed to get expected results. Check out SQL Performance Tuning by Peter Gulutzan and Trudy Pelzer for more info about JOINS. Hope this helps.
Kind regards,
Gift Peddie
Kind regards,
Gift Peddie
September 27, 2005 at 12:20 pm
That is interesting behavior, especially when COALESCE works. Note that if you change the constant in the view to a case statement, the isnull join works as expected.
View vw AS SELECT ID, case when ID<5 then 1 else null end As Val FROM tbl WHERE ID < 5
September 27, 2005 at 12:31 pm
Actually use "ID>0" in the case statement, then you just have to modify the where clause
September 28, 2005 at 1:55 am
When does 'interesting behaviour' get to be a bug?
When ISNULL(Val, 0) returns 1 when val returns NULL, that is a bug.
Thanks for the input guys. If I had the energy I might see what Microsoft has to say about it, but I have to move on.
Andy
September 28, 2005 at 2:30 am
optimists read no further
after a few phonecalls ... please give complete core dumps of everything your'e doing ... followed a week later by yes, the guys know about that one, but everyone's trying to get sql 2005 to work ... followed a few days later by ... hello, were you satisfied with your microsoft support ?
September 28, 2005 at 2:35 am
Exactly
ttfn
September 28, 2005 at 3:29 am
The results may be slightly unexpected, but if you look at "View Resolution" in BOL, it might explain what SQL Server is actually doing! Remember that a View isn't a table, it's effectively a sub-query when used in a query!
September 28, 2005 at 4:09 am
I am sure there are explanations for its mis-behaviour, but to me its more than 'slightly unexpected'. Yes, I am sure that under the lid there may be indicators that things are not what they seem, but should I have to root around to justify it?
It may be that a view isnt a table but a sub-query. It may be that the View Resolution in BOL explains what SQL Server is actually doing. Nevertheless, in a sane and ordered world, ISNULL(Val,0) should return the same as COALESCE(Val,0).
Maybe I ask too much.
September 28, 2005 at 7:53 am
The query optimiser may be applying the WHERE in the view after the ISNULL.
In the SQL Server engine, then there is no guarantee of the JOIN being executed before the WHERE and vice versa.
Example:
SELECT * FROM tbl1 LEFT OUTER JOIN tbl2 ON tbl1.col = tbl2.col WHERE tbl2.col IS NULL
may not return nonmatching rows, but this will
SELECT * FROM tbl1 LEFT OUTER JOIN tbl2 ON tbl1.col = tbl2.col OR tbl2.col IS NULL
In this instance, try the NOEXPAND hint on the view to change how SQL evaluates the query:
SELECT tbl.ID, Val, ISNULL(Val,0) As [Val2]
FROM tbl LEFT OUTER JOIN vw (NOEXPAND) ON tbl.ID=vw.ID
I guess that COALESCE or CASE also changes how SQL evaluates the query.
All code untested!
Viewing 15 posts - 1 through 15 (of 28 total)
You must be logged in to reply to this topic. Login to reply