locked
Checking for NULL RRS feed

  • Question

  • Hi

    When I use below in WHERE clause in a SELECT it fails when Role is NULL;

    SELECT *
    FROM tblStaffBookings
    WHERE  .... AND (tblStaffBookings.[Role] <> 'Available')

    Why doesn't tblStaffBookings.[Role] <> 'Available' come out as TRUE when tblStaffBookings.[Role] is NULL? How do I get round it? At present I am using;

    SELECT *
    FROM tblStaffBookings
    WHERE  .... AND (tblStaffBookings.[Role] <> 'Available' OR tblStaffBookings.[Role] IS NULL)

    Thanks

    Regards


    • Edited by Y a h y a Wednesday, December 16, 2015 9:19 PM
    Wednesday, December 16, 2015 9:18 PM

Answers

  • comparison (NULL = something) or (NULL <> something) always returns False, just keep this in mind.

    you can use your way or you can use ISNULL() function as well:

    SELECT *
    FROM tblStaffBookings
    WHERE  .... AND isnull(tblStaffBookings.[Role], '') <> 'Available'




    • Edited by S.Khanzhin Wednesday, December 16, 2015 9:30 PM
    • Proposed as answer by Eric__Zhang Thursday, December 17, 2015 6:16 AM
    • Marked as answer by Eric__Zhang Thursday, December 24, 2015 8:28 AM
    Wednesday, December 16, 2015 9:27 PM
  • you can write something like below

    SELECT *
    FROM tblStaffBookings
    WHERE  .... AND (isnull(tblStaffBookings.[Role],'NA') <> 'Available')


    Cheers,

    Amit Tomar

    ---------------------------------------------------

    Please mark this as answer if it solved your query

    Please vote this as helpful if it solved your query

    ---------------------------------------------------

    My Blog My Wiki Page

    • Proposed as answer by Eric__Zhang Thursday, December 17, 2015 6:17 AM
    • Marked as answer by Eric__Zhang Thursday, December 24, 2015 8:29 AM
    Thursday, December 17, 2015 1:42 AM

All replies

  • comparison (NULL = something) or (NULL <> something) always returns False, just keep this in mind.

    you can use your way or you can use ISNULL() function as well:

    SELECT *
    FROM tblStaffBookings
    WHERE  .... AND isnull(tblStaffBookings.[Role], '') <> 'Available'




    • Edited by S.Khanzhin Wednesday, December 16, 2015 9:30 PM
    • Proposed as answer by Eric__Zhang Thursday, December 17, 2015 6:16 AM
    • Marked as answer by Eric__Zhang Thursday, December 24, 2015 8:28 AM
    Wednesday, December 16, 2015 9:27 PM
  • comparison (NULL = something) or (NULL <> something) always returns False,

    To be picky, those comparison returns UNKNOWN, not FALSE. The net result is the same in this case, though.

    Wednesday, December 16, 2015 10:57 PM
  • Your 'workaround' is the right way to go about things. 

    In SQL, NULL is an often misunderstood concept.  It's definition essentially is that of the absence of a value.  NULL is not a value, and one NULL is not equal to (nor unequal to) another NULL, because we don't know what it is (or isn't, for that case)

    As a result the following...

    tblStaffBookings.Role <> 'Available'

    ..won't return NULL. The reason for this is that we can't be sure that NULL is equal to, nor unequal to, ANYTHING...it's a bizarre concept but one that makes more sense the more you work with it.

    Basically you just have to accept that NULL is neither equal to, nor unequal to anything else and its presence can only be tested by using IS NULL, or converting NULL to something else that can be tested using ISNULL or COALESCE functions.

    Hope this is helpful and not more confusing to you.




    • Proposed as answer by Naomi N Wednesday, December 16, 2015 11:11 PM
    • Edited by matprichardson Wednesday, December 16, 2015 11:15 PM
    Wednesday, December 16, 2015 11:02 PM
  • you can write something like below

    SELECT *
    FROM tblStaffBookings
    WHERE  .... AND (isnull(tblStaffBookings.[Role],'NA') <> 'Available')


    Cheers,

    Amit Tomar

    ---------------------------------------------------

    Please mark this as answer if it solved your query

    Please vote this as helpful if it solved your query

    ---------------------------------------------------

    My Blog My Wiki Page

    • Proposed as answer by Eric__Zhang Thursday, December 17, 2015 6:17 AM
    • Marked as answer by Eric__Zhang Thursday, December 24, 2015 8:29 AM
    Thursday, December 17, 2015 1:42 AM
  • SELECT *
    FROM tblStaffBookings
    WHERE  .... AND (tblStaffBookings.[Role] <> 'Available' OR tblStaffBookings.[Role] IS NULL)

    This is the correct way. You have it right.
    • Proposed as answer by Jason A Long Thursday, December 17, 2015 10:12 PM
    Thursday, December 17, 2015 4:39 AM
  •  everytime have a problem with "null" query

    i think you first use SET ANSI_NULLS  standart from ANSI SQL

    for example you query will with this model

    set ANSI_NULLS off
    
    /* your sql query */
    
    
    set ANSI_NULLS on


    and see my wiki page 

    http://social.technet.microsoft.com/wiki/contents/articles/32663.sql-server-troubleshooting-select-from-null-rows.aspx

     

    Thursday, December 17, 2015 6:51 AM
  • i think you first use SET ANSI_NULLS  standart from ANSI SQL

    Please, don't ever mess with SET ANSI_NULLS and even less suggest this in public!

    SET ANSI_NULLS OFF is a legacy setting for application writtn in the nineties and who still have not mended their ways. There are several points of functionality in SQL Server that does not work when ANSI_NULLS is OFF:

    * Queries with linked servers.
    * XQuery and the xml type methods.
    * Indexed views.
    * Filtered indexes.
    * XML indexes.
    * Spatial indexes.

    There may be more.

    If run with ANSI_NULLS off you will be burnt sooner or later.

    • Proposed as answer by Jason A Long Thursday, December 17, 2015 10:13 PM
    Thursday, December 17, 2015 8:17 AM
  • WHERE  .... AND (COALESCE(tblStaffBookings.[Role],'Not Available') <> 'Available')

    COALESCE returns the first NON NULL value. In this case if Role IS NULL it will return Not available, which is evaluated in the <> 'Available' and will return true.

    I'd also like to introduce you to aliasing.

    SELECT *
      FROM myReallyLongTableNameOfGreatDoomAndWorry d
     WHERE d.col = 1
    In this example I have a table with a long name. I don't want to have to use that long name to refer to it all the time, so I've given it the ALIAS d. Now I can refer to it using that ALIAS.



    Don't forget to mark helpful posts, and answers. It helps others to find relevant posts to the same question. Enjoyed my post? Hit the up arrow (left)
    Really enjoyed it? See my profile!
    My Tech Net Articles.


    Thursday, December 17, 2015 2:23 PM
  • Please, don't ever mess with SET ANSI_NULLS and even less suggest this in public!

    I'm pretty sure if you mess with ANSI_NULLS they send Celko to your christmas party. I'm also pretty sure he brings his whomping stick.

    Don't forget to mark helpful posts, and answers. It helps others to find relevant posts to the same question. Enjoyed my post? Hit the up arrow (left)
    Really enjoyed it? See my profile!
    My Tech Net Articles.

    Thursday, December 17, 2015 2:24 PM
  • ... and I'm sure it won't be pretty!

    • Proposed as answer by Naomi N Sunday, December 20, 2015 8:00 PM
    • Unproposed as answer by Naomi N Sunday, December 20, 2015 8:00 PM
    Thursday, December 17, 2015 9:07 PM
  • WHERE  .... AND (COALESCE(tblStaffBookings.[Role],'Not Available') <> 'Available')

    Using the COALESCE in the WHERE clause should be a no no... It make the predicate non-sargable.

    The preferred syntax should be as the OP had it in his 2nd example...

    WHERE  .... AND (tblStaffBookings.[Role] <> 'Available' OR tblStaffBookings.[Role] IS NULL)


    Jason Long

    • Proposed as answer by Naomi N Sunday, December 20, 2015 7:59 PM
    Thursday, December 17, 2015 10:22 PM
  • Please, don't ever mess with SET ANSI_NULLS and even less suggest this in public!

    I'm pretty sure if you mess with ANSI_NULLS they send Celko to your christmas party. I'm also pretty sure he brings his whomping stick.

    Don't forget to mark helpful posts, and answers. It helps others to find relevant posts to the same question. Enjoyed my post? Hit the up arrow (left)
    Really enjoyed it? See my profile!
    My Tech Net Articles.

    But I always bring a bag of coal for the children when I  go to Christmas parties :-)

    On a more serious note, it might be a good idea to address the encoding that allows something to be null. Since it seems to be a list of codes of some kind, the encoding might include a "N/A", "miscellaneous", "missing" or whatever.

    --CELKO-- Books in Celko Series for Morgan-Kaufmann Publishing: Analytics and OLAP in SQL / Data and Databases: Concepts in Practice Data / Measurements and Standards in SQL SQL for Smarties / SQL Programming Style / SQL Puzzles and Answers / Thinking in Sets / Trees and Hierarchies in SQL

    Thursday, December 17, 2015 10:53 PM
  • Please correct me if I'm wrong, but doesn't the engine switch COALESCE out for a CASE behind the scenes, meaning that it actually IS sargable?

    Also, regardless of the sargability (is that a word? it should be!) would this only be applicable if the column has an index on it? If it's a varchar with NULL and repeated values, I think the chances of an index are pretty slim :)


    Don't forget to mark helpful posts, and answers. It helps others to find relevant posts to the same question. Enjoyed my post? Hit the up arrow (left)
    Really enjoyed it? See my profile!
    My Tech Net Articles.

    Friday, December 18, 2015 2:11 PM

  • But I always bring a bag of coal for the children when I  go to Christmas parties :-)

    On a more serious note, it might be a good idea to address the encoding that allows something to be null. Since it seems to be a list of codes of some kind, the encoding might include a "N/A", "miscellaneous", "missing" or whatever.

    --CELKO-- Books in Celko Series for Morgan-Kaufmann Publishing: Analytics and OLAP in SQL / Data and Databases: Concepts in Practice Data / Measurements and Standards in SQL SQL for Smarties / SQL Programming Style / SQL Puzzles and Answers / Thinking in Sets / Trees and Hierarchies in SQL

    Guys! A NICE Celko post! See, Christmas miracles do happen! Merry Christmas Joe!

    Don't forget to mark helpful posts, and answers. It helps others to find relevant posts to the same question. Enjoyed my post? Hit the up arrow (left)
    Really enjoyed it? See my profile!
    My Tech Net Articles.

    Friday, December 18, 2015 2:12 PM

  • But I always bring a bag of coal for the children when I  go to Christmas parties :-)

    On a more serious note, it might be a good idea to address the encoding that allows something to be null. Since it seems to be a list of codes of some kind, the encoding might include a "N/A", "miscellaneous", "missing" or whatever.

    --CELKO-- Books in Celko Series for Morgan-Kaufmann Publishing: Analytics and OLAP in SQL / Data and Databases: Concepts in Practice Data / Measurements and Standards in SQL SQL for Smarties / SQL Programming Style / SQL Puzzles and Answers / Thinking in Sets / Trees and Hierarchies in SQL

    Guys! A NICE Celko post! See, Christmas miracles do happen! Merry Christmas Joe!

    Don't forget to mark helpful posts, and answers. It helps others to find relevant posts to the same question. Enjoyed my post? Hit the up arrow (left)
    Really enjoyed it? See my profile!
    My Tech Net Articles.

    I second that! LOL
    Friday, December 18, 2015 7:08 PM
  • Please correct me if I'm wrong, but doesn't the engine switch COALESCE out for a CASE behind the scenes, meaning that it actually IS sargable?

    Also, regardless of the sargability (is that a word? it should be!) would this only be applicable if the column has an index on it? If it's a varchar with NULL and repeated values, I think the chances of an index are pretty slim :)


    Don't forget to mark helpful posts, and answers. It helps others to find relevant posts to the same question. Enjoyed my post? Hit the up arrow (left)
    Really enjoyed it? See my profile!
    My Tech Net Articles.

    You are correct that a COALESCE is just a CASE expression with an alternate syntax.

    No... Neither a COALESCE nor a CASE expression in the WHERE clause are sargable. In fact, off the top of my head, the only two functions that are sargable are CAST & CONVERT. And even then it only works with certain datatypes.

    Is sargability as word?  I get the red squiggly in all browsers and MS Word... But if you ask Google to find sargibility  it'll ask if you mean sargability... So I suppose it depends on who's dictionary you're using...

    Yes... You are correct in saying that, if no index exists on the column, then it doesn't matter... But that's a big IF. There's nothing that would or should keep a nullable (another iffy word) column from being an index key.

    In either case, using functions in the WHERE clause is just a bad habit. Even if there isn't an index on that column today, doesn't mean that one won't be created down the road.

    Below is a quick little demo...

    IF OBJECT_ID('tempdb..#temp', 'U') IS NOT NULL 
    DROP TABLE #temp;
    
    CREATE TABLE #temp (
    	FirstNumber INT NOT NULL PRIMARY KEY,
    	SecondNumber INT NULL 
    	);
    -- run with & without the nonclustered index --
    CREATE NONCLUSTERED INDEX ix_temp ON #temp (SecondNumber) INCLUDE (FirstNumber);
    GO 
    
    WITH n (n) AS (
    	SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (n)
    ), Tally (n) AS (
    	SELECT 
    		ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
    	FROM n n1, n n2, n n3, n n4, n n5, n n6
    )
    INSERT #temp (FirstNumber,SecondNumber)
    SELECT 
    	t.n,
    	CASE WHEN t.n % 10 > 0 THEN t.n END
    FROM 
    	Tally t
    ;
    
    --=======================================================================
    
    DECLARE 
    	@n INT,
    	@b1 DATETIME2(7),
    	@b2 DATETIME2(7)
    ;
    
    SET @b1 = SYSDATETIME();
    SELECT 
    	@n = t.FirstNumber
    FROM 
    	#temp t
    WHERE 
    	t.SecondNumber < 10000 OR t.SecondNumber IS NULL
    ;
    
    SET @b2 = SYSDATETIME();
    SELECT 
    	@n = t.FirstNumber
    FROM 
    	#temp t
    WHERE 
    	COALESCE(t.SecondNumber, 0) < 10000
    ;
    
    SELECT 
    	DATEDIFF(ms, @b1, @b2) AS Query_1,
    	DATEDIFF(ms, @b2, SYSDATETIME()) AS Query_2
    ;
    
    
    

    In any case... Hope I didn't come off as a ball buster. The only reason I harp on it is because it's one of my own personal bad habits that I have to keep reminding myself to break. The COALESCE syntax makes for cleaner looking code... Which make too damn tempting... 


    Jason Long

    • Proposed as answer by Naomi N Sunday, December 20, 2015 8:01 PM
    Friday, December 18, 2015 11:14 PM
  • Personally, I think "sargable" or however you would spell it is a useless word. What matters is whether any index can or will be seeked.

    Consider this script:

    SELECT * INTO objects FROM sys.objects
    CREATE CLUSTERED INDEX clu ON objects(create_date)
    ALTER TABLE objects ADD CONSTRAINT pk_objects PRIMARY KEY (object_id)
    go
    SELECT * FROM objects WHERE create_date > '20020101' AND create_date < '20030101'
    SELECT * FROM objects WHERE year(create_date) = 2002
    SELECT * FROM objects WHERE month(create_date) = 12
    go
    DROP TABLE objects

    As it happens, the clustered index is only seeked in the first query. Still there is a fundamental difference between the second and the third query. From a logical point of view, the index could be seeked, if the optimizer only cared to make the transformation and not just give up. But in the third query, there is not the ghost of a chance, as the condition is not aligned with the index.

    • Proposed as answer by Ahsan KabirMVP Sunday, December 20, 2015 5:02 AM
    Saturday, December 19, 2015 10:58 AM