• No problem Dave.  There is a difference between NOT EXISTS and NOT IN in some cases.  Consider the following sample:

    CREATE TABLE #test (id INT PRIMARY KEY,

     val VARCHAR(20));

    INSERT INTO #test (id, val)

    SELECT 1, 'One'

    UNION SELECT 2, 'Two'

    UNION SELECT 3, 'Three'

    UNION SELECT 4, 'Four'

    UNION SELECT 5, 'Five';

    CREATE TABLE #odd (id INT);

    CREATE NONCLUSTERED INDEX ix1

    ON #odd(id);

    go

    WITH Num (n)

    AS

    (

     SELECT 1

     UNION ALL

     SELECT n + 1

     FROM Num

     WHERE n < 10000

    )

    INSERT INTO #odd (id)

    SELECT n

    FROM Num

    OPTION (MAXRECURSION 0)

    go

    SELECT *

    FROM #odd

    WHERE id NOT IN (

     SELECT id

     FROM #test

    );

    go

    SELECT *

    FROM #odd

    WHERE NOT EXISTS (

     SELECT id

     FROM #test

     WHERE #test.id = #odd.id

    );

    go

    drop table #test;

    drop table #odd;

    On my computer it generates two different query plans.  NOT EXISTS generates a query plan with a cost of 0.0614788.  NOT IN generates a query plan with substantially higher cost of 0.121561.  For small data sets in both tables the two queries generated the same query plan.

    EXISTS is not just about breaking the loop, the SELECT in EXISTS uses a correlated subquery and can potentially take advantage of indexes on the table.  In the best case this could result in efficient index seeks in the subquery, depending on which query plan SQL Server decides to go with.