When to use EXCEPT as opposed to NOT EXISTS in Transact SQL?

后端 未结 5 1309
甜味超标
甜味超标 2020-11-30 05:45

I just recently learned of the existence of the new \"EXCEPT\" clause in SQL Server (a bit late, I know...) thru reading code written by a coworker. It truly amazed me!

5条回答
  •  无人及你
    2020-11-30 06:19

    EXCEPT treats NULL values as matching.

    This query:

    WITH    q (value) AS
            (
            SELECT  NULL
            UNION ALL
            SELECT  1
            ),
            p (value) AS
            (
            SELECT  NULL
            UNION ALL
            SELECT  2
            )
    SELECT  *
    FROM    q
    WHERE   value NOT IN
            (
            SELECT  value
            FROM    p
            )
    

    will return an empty rowset.

    This query:

    WITH    q (value) AS
            (
            SELECT  NULL
            UNION ALL
            SELECT  1
            ),
            p (value) AS
            (
            SELECT  NULL
            UNION ALL
            SELECT  2
            )
    SELECT  *
    FROM    q
    WHERE   NOT EXISTS
            (
            SELECT  NULL
            FROM    p
            WHERE   p.value = q.value
            )
    

    will return

    NULL
    1
    

    , and this one:

    WITH    q (value) AS
            (
            SELECT  NULL
            UNION ALL
            SELECT  1
            ),
            p (value) AS
            (
            SELECT  NULL
            UNION ALL
            SELECT  2
            )
    SELECT  *
    FROM    q
    EXCEPT
    SELECT  *
    FROM    p
    

    will return:

    1
    

    Recursive reference is also allowed in EXCEPT clause in a recursive CTE, though it behaves in a strange way: it returns everything except the last row of a previous set, not everything except the whole previous set:

    WITH    q (value) AS
            (
            SELECT  1
            UNION ALL
            SELECT  2
            UNION ALL
            SELECT  3
            ),
            rec (value) AS
            (
            SELECT  value
            FROM    q
            UNION ALL
            SELECT  *
            FROM    (
                    SELECT  value
                    FROM    q
                    EXCEPT
                    SELECT  value
                    FROM    rec
                    ) q2
            )
    SELECT  TOP 10 *
    FROM    rec
    
    ---
    1
    2
    3
    -- original set
    1
    2
    -- everything except the last row of the previous set, that is 3
    1
    3
    -- everything except the last row of the previous set, that is 2
    1
    2
    -- everything except the last row of the previous set, that is 3, etc.
    1
    

    SQL Server developers must just have forgotten to forbid it.

提交回复
热议问题