I have a MySQL query that joins two tables
They join on voters.household_id
and household.id
.
Now what I need to do is to modify it where the voter table is joined to a third table called elimination, along voter.id
and elimination.voter_id
. However the catch is that I want to exclude any records in the voter table that have a corresponding record in the elimination table.
How do I craft a query to do this?
This is my current query:
SELECT `voter`.`ID`, `voter`.`Last_Name`, `voter`.`First_Name`, `voter`.`Middle_Name`, `voter`.`Age`, `voter`.`Sex`, `voter`.`Party`, `voter`.`Demo`, `voter`.`PV`, `household`.`Address`, `household`.`City`, `household`.`Zip` FROM (`voter`) JOIN `household` ON `voter`.`House_ID`=`household`.`id` WHERE `CT` = '5' AND `Precnum` = 'CTY3' AND `Last_Name` LIKE '%Cumbee%' AND `First_Name` LIKE '%John%' ORDER BY `Last_Name` ASC LIMIT 30
The WHERE NOT EXISTS() subquery will only return rows where the relationship is not met. However, if you did a LEFT OUTER JOIN and looked for IS NULL on the foreign key column in the WHERE clause, you can make equivalent behavior to the WHERE NOT EXISTS .
Such joins are called non-equi JOINs, and they are also possible in SQL. When you join two tables using other conditional operators, beyond the equal sign, non-equi JOINs come into play. Comparison operators, like <, >, <=, >=, != , and <> and the BETWEEN operator work perfectly for joining tables in SQL.
Note that the full-outer join is not supported by MySQL although you can emulate one by combining left and right-outer join with UNION set operation. Oracle and SQL Server do support the full-outer join.
Yes, you can! The longer answer is yes, there are a few ways to combine two tables without a common column, including CROSS JOIN (Cartesian product) and UNION.
I'd probably use a LEFT JOIN
, which will return rows even if there's no match, and then you can select only the rows with no match by checking for NULL
s.
So, something like:
SELECT V.* FROM voter V LEFT JOIN elimination E ON V.id = E.voter_id WHERE E.voter_id IS NULL
Whether that's more or less efficient than using a subquery depends on optimization, indexes, whether its possible to have more than one elimination per voter, etc.
I'd use a 'where not exists' -- exactly as you suggest in your title:
SELECT `voter`.`ID`, `voter`.`Last_Name`, `voter`.`First_Name`, `voter`.`Middle_Name`, `voter`.`Age`, `voter`.`Sex`, `voter`.`Party`, `voter`.`Demo`, `voter`.`PV`, `household`.`Address`, `household`.`City`, `household`.`Zip` FROM (`voter`) JOIN `household` ON `voter`.`House_ID`=`household`.`id` WHERE `CT` = '5' AND `Precnum` = 'CTY3' AND `Last_Name` LIKE '%Cumbee%' AND `First_Name` LIKE '%John%' AND NOT EXISTS ( SELECT * FROM `elimination` WHERE `elimination`.`voter_id` = `voter`.`ID` ) ORDER BY `Last_Name` ASC LIMIT 30
That may be marginally faster than doing a left join (of course, depending on your indexes, cardinality of your tables, etc), and is almost certainly much faster than using IN.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With