tags:

views:

1902

answers:

5

I'm trying write a query to find records which don't have a matching record in another table.

For example, I have a two tables whose structures looks something like this:

Table1
    State | Product | Distributor | other fields
    CA    | P1      |  A          | xxxx
    OR    | P1      |  A          | xxxx
    OR    | P1      |  B          | xxxx
    OR    | P1      |  X          | xxxx
    WA    | P1      |  X          | xxxx
    VA    | P2      |  A          | xxxx

Table2
    State | Product | Version | other fields
    CA    | P1      |  1.0    | xxxx
    OR    | P1      |  1.5    | xxxx
    WA    | P1      |  1.0    | xxxx
    VA    | P2      |  1.2    | xxxx

(State/Product/Distributor together form the key for Table1. State/Product is the key for Table2)

I want to find all the State/Product/Version combinations which are Not using distributor X. (So the result in this example is CA-P1-1.0, and VA-P2-1.2.)

Any suggestions on a query to do this?

+8  A: 
SELECT
    *
FROM
    Table2 T2
WHERE
    NOT EXISTS (SELECT *
        FROM
           Table1 T1
        WHERE
           T1.State = T2.State AND
           T1.Product = T2.Product AND
           T1.Distributor = 'X')

Edit: Damn: beaten to it. This should be ANSI compliant though.

gbn
This works on most SQL systems; EXCEPT won't work everywhere (though it is more elegant where it does work).
Jonathan Leffler
Using "SELECT 1 FROM" in the sub-query (instead of "SELECT * FROM") may prevent an unnecessary table scan. Though I would expect the DBMS to be smart enough to figure it out on it's own, upon seeing "EXISTS".
Tomalak
I have this with my SQL Server MVP colleague all the time :-) The * is expanded at compile time, bt collapses trivially, but not runtime he says. He showed me an article once. I saw Itzak Ben-Gan a while ago and he said the * is quicker. The choice is yours...
gbn
Worked well. Thanks.
Boofus McGoofus
When using EXISTS there should be no difference between SELECT * and SELECT 1.
Dems
A: 

select * from table1 where state not in (select state from table1 where distributor = 'X')

Probably not the most clever but that should work.

Tundey
IN is not as good as EXISTS, and does not handle the composite key on state/product
gbn
+2  A: 

In T-SQL:

SELECT DISTINCT Table2.State, Table2.Product, Table2.Version
FROM Table2 
  LEFT JOIN Table1 ON Table1.State = Table2.State AND Table1.Product = Table2.Product AND Table1.Distributor = 'X'
WHERE Table1.Distributor IS NULL

No subqueries required.

Edit: As the comments indicate, the DISTINCT is not necessary. Thanks!

mwigdahl
I wouldn't use distinct, but otherwise this is what you want.
HLGEM
The distinct will probably make the query less efficient, but never more efficient. It depends on the relative table row counts. The distcnt also forces an aggregate that sub query does not need.
gbn
A: 
SELECT DISTINCT t2.State, t2.Product, t2.Version
FROM table2 t2
JOIN table1 t1 ON t1.State = t2.State AND t1.Product = t2.Product
                AND t1.Distributor <> 'X'
Mr. Brownstone
A: 

In Oracle:

SELECT t2.State, t2.Product, t2.Version
FROM Table2 t2, Table t1
WHERE t1.State(+) = t2.State
  AND t1.Product(+) = t2.Product
  AND t1.Distributor(+) = :distributor
  AND t1.State IS NULL
Quassnoi