Search code examples
sqlsql-serversubquerysql-server-2017sql-null

Query not returning expected data


I'm looking for an explanation for why 1 of the following 3 queries aren't returning what I am expecting.

-- Query 1
SELECT ANNo, ANCpr
FROM Anmodning
WHERE LEFT(ANCpr,6) + '-' + RIGHT(ANCpr,4) NOT IN (SELECT PSCpr FROM Person)

-- Query 2
SELECT ANNo, ANCpr
FROM Anmodning a
LEFT JOIN Person p ON p.PSCpr = LEFT(a.ANCpr,6) + '-' + RIGHT(a.ANCpr,4)
WHERE p.PSNo IS NULL

-- Query 3
SELECT ANNo, ANCpr
FROM Anmodning
WHERE ANNo NOT IN
(
  SELECT ANNo
  FROM Anmodning
  WHERE LEFT(ANCpr,6) + '-' + RIGHT(ANCpr,4) IN (SELECT PSCpr FROM Person)
)

Assume the following:
Anmodning with ANNo=1, ANCpr=1111112222
And the Person table doesn't have a row with PSCpr=111111-2222
Queries are executed in Management Studio against a SQL Server 2017.

Queries 2 and 3 returns the Anmodning row as expected but query 1 does not. Why is that?


Solution

  • I suspect the issue with the first query is a null-safety problem. If there are null values in Person(PSCpr), then the not in condition filters out all Anmodning rows, regardless of other values in Person.

    Consider this simple example:

    select 1 where 1 not in (select 2 union all select null)
    

    Returns no rows, while:

    select 1 where 1 not in (select 2 union all select 3)
    

    Returns 1 as you would expect.

    This problem does not happen when you use left join, as in the second query.

    You could also phrase this with not exists, which is null-safe, which I would recommend here:

    SELECT ANNo, ANCpr
    FROM Anmodning a
    WHERE NOT EXITS (SELECT 1 FROM Person p WHERE p.PSCpr = LEFT(a.ANCpr,6) + '-' + RIGHT(a.ANCpr,4))