views:

152

answers:

4

Say I have two tables called A (fields: id, phase, name) and B(fields: id, AID, APHASE, void).

I need to show all records from A except for records where A.id = B.AID and A.phase = B.APHASE and void = 0.

Environment is MySQL.

A: 

fixed I guess :\

select * from A, B

where

not( A.id = B.AID and A.phase = B.APHASE and void = 0 )

Am getting old :|

effkay
Not a good solution. Ignore phase and void temporarily. Suppose there is one row in table A with id = 1, and there are three rows in table B with (id = 1, aid = 1), (id = 2, aid = 1), (id = 3, aid = 2). This query will generate a result row but shouldn't to answer the question. The NOT EXISTS queries will generate no rows - which is the correct result.
Jonathan Leffler
+1  A: 
SELECT  *
FROM    A
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    B
        WHERE   b.aid = a.id
                AND b.aphase = a.phase
                AND b.void = 0
        )

Note that this query will always return each rows from A exactly 1 or 0 times.

The LEFT JOIN can return rows from A many times if B (aid, aphase) is not UNIQUE.

These queries have different semantics, so choosing a correct one is a matter of validity, not performance.

As for performance, MySQL will always use A as a leading table since it's not capable of doing joins in other way than NESTED LOOPS.

Since EXISTS will always return as soon as it finds a first matching record, EXISTS query will always be more efficient than a LEFT JOIN (just because it returns at least not later than a LEFT JOIN), at expense of returning at most one record from A.

Quassnoi
`NOT EXISTS` can be pretty slow
knittl
`@knittl`: In `MySQL` (namely in `MySQL`) it cannot be any more slow than a `LEFT JOIN` (namely `LEFT JOIN`).
Quassnoi
+1  A: 
SELECT 
    id, phase, name 
FROM A 
WHERE NOT EXISTS 
    (SELECT id FROM B WHERE AID=A.id AND APHASE=A.phase AND void=0)
janoliver
+1  A: 
   SELECT *
     FROM `A`
LEFT JOIN `B`
       ON `A`.`id` = `B`.`id`
    WHERE NOT ( `A`.`id` = `B`.`AID` AND `A`.`phase` = `B`.`APHASE`
                AND `void` = 0 )

or:

   SELECT *
     FROM `A`
LEFT JOIN `B`
       ON NOT ( `A`.`id` = `B`.`AID`
                AND `A`.`phase` = `B`.`APHASE`
                AND `void` = 0 )

no guarantee the second one actually works, it just came to my mind

knittl
Hey - do the two tables join on a.id = b.id, or do they join on 'a.id = b.aid'? The question isn't clear on this - but your answer is assuming the id rows join, whereas the naming suggests otherwise.
Jonathan Leffler
i’m not quite sure, but i think the second statement describes the question. if it’s not working correctly effkay can always comment back
knittl
There's an element of "he already did" - your answer is selected. The second option should probably list A.* in the SELECT list. I'm worried about the cardinality of the result (see comment to author's "answer"). And I think the 'AND void = 0' bit should be inside the 'NOT (...)' parentheses.
Jonathan Leffler
ah whops. edited
knittl