Using a CTE in a subquery

  • I have been tasked with identifying a set of users in one of our databases.  The following code should be reasonably self-explanatory:

    --There are 1,360 Users 
    SELECT COUNT(*) AS NumUsers FROM Users;

    -- Use a CTE to identify all Users who are linked to Actions - there are 82 of these
    ;WITH ActionCentreUsers AS
    (
    SELECT DISTINCT UserID AS UserId FROM ActionPlans
    UNION
    SELECT DISTINCT CreatorId AS UserId FROM Actions
    UNION
    SELECT DISTINCT AssignorId AS UserId FROM Actions
    UNION
    SELECT DISTINCT ModifiedBy AS UserId FROM Actions
    )

    --This JOIN returns 82 rows
    SELECT * FROM Users INNER JOIN ActionCentreUsers ON Users.UserId = ActionCentreUsers.UserId

    -- As a result of the above, I would expect this to return 1,360 - 82 = 1278. It actually returns 0 rows
    SELECT * FROM Users WHERE UserId NOT IN (SELECT UserId FROM ActionCentreUsers)

    -- This, on the other hand, returns 1,278 rows
    SELECT * FROM Users LEFT JOIN ActionCentreUsers ON Users.UserId = ActionCentreUsers.UserId WHERE ActionCentreUsers.UserId IS NULL

    I realise that a CTE falls out of scope once used, so in testing I've commented out the successive SELECT statements.  My question is, why does this statement return 0 rows?

    SELECT * FROM Users WHERE UserId NOT IN (SELECT UserId FROM ActionCentreUsers

    Many thanks

    Edward

     

     

  • I bet at least one of the values of UserID in your CTE ActionCentreUsers has the value NULL. If so, that is documented behaviour:

    Caution

    Any null values returned by subquery or expression that are compared to test_expression using IN or NOT IN return UNKNOWN. Using null values in together with IN or NOT IN can produce unexpected results.

    Try using NOT EXISTS instead.

    Thom~

    Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
    Larnu.uk

  • Ah thanks Thom.  I've already replaced the CTE with a table variable (as it turns out I need to reference it multiple times in a much more detailed batch) and the NULL value bit me.  So that's good to know!

  • Rather than a variable, seems like you'd be better off with a VIEW.

    Thom~

    Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
    Larnu.uk

  • If there were any need to persist this, then I'd agree.  However, the script is merely to identify a set of users for later deletion.  The circumstances which have given rise to this requirement will not recur, and so there's no need for this to exist beyond today.

  • Also, get rid of the DISTINCTUNION already does a distinct, so specifying DISTINCT here just clutters up your code with no benefit.

    Drew

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

  • drew.allen wrote:

    Also, get rid of the DISTINCTUNION already does a distinct, so specifying DISTINCT here just clutters up your code with no benefit.

    Drew

    Good spot Drew.

    Thom~

    Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
    Larnu.uk

Viewing 7 posts - 1 through 6 (of 6 total)

You must be logged in to reply to this topic. Login to reply