Reputation: 3717
I have two tables, as follows:
People:
First_Name Last_Name
Bill Smith
David Williams
Fred Jones
Freda Jones
Jane Smith
John Smith
Peter Williams
Sally Williams
Pets:
Species Title Owner
Dog Fido Jones
Cat Tibs Jones
Dog Jock Williams
I know it's a weird database design, but please don't tell me to redesign the database. It's an example that represents the real problem, which is more complicated and can't be redesigned.
I am trying to formulate a query that will return exactly one row for each person, and a column containing the title of their Cat or null if they do not own a cat (I used Title
because Name
is a reserved word and Access complained).
The nearest I have come up with is:
SELECT People.*, Pets.Title
FROM People
LEFT JOIN Pets ON People.Last_Name = Pets.Owner
WHERE Pets.Species IS NULL OR Pets.Species = "Cat"
However this doesn't list any rows for the Williams family because they own a dog.
I have tagged this as MS Access because I am actually using Access 97 (don't ask!), but, other than Access's rather limited Join facilities, it should be a general SQL question.
Upvotes: 1
Views: 52
Reputation: 3717
For posterity - I finally got it:
SELECT People.*, Pets.Title FROM
People LEFT JOIN (SELECT * FROM Pets WHERE Species='Cat') AS PeopleWithCats
ON People.Last_Name=PeopleWithCats.Owner
Upvotes: 0
Reputation: 180887
EDIT: The left join syntax in Access causes trouble, which means that for access we need to involve a subquery. This will look something like (the untested);
SELECT People.*, Pets.Title
FROM People LEFT JOIN
[SELECT Pets.* FROM Pets WHERE Pets.Species = 'Cat']. AS Pets
ON People.Last_Name = Pets.Owner
-- Original answer --
What you seem to want is a regular left join with an additional condition that the pet needs to be a cat;
SELECT People.*, Pets.Title
FROM People LEFT JOIN Pets
ON People.Last_Name = Pets.Owner AND Pets.Species = 'Cat'
The reason for not putting the cat condition in a WHERE
clause is that a where clause eliminates all non matches, while putting it in the ON
clause makes the result NULL if it can't find a match (just as you describe your desired result)
Upvotes: 5
Reputation: 8545
Try this
SELECT People.*, case when Pets.Species = 'Cat' then Pets.Title else null end as Title
FROM People LEFT JOIN Pets ON People.Last_Name = Pets.Owner
Upvotes: 0
Reputation: 218818
this doesn't list any rows for the Williams family because they own a Dog
That's because of the WHERE
clause:
WHERE Pets.Species IS NULL OR Pets.Species = "Cat"
If Pets.Species
is "Dog"
then this would evaluate to false, so those records are not shown. First remove the clause entirely:
SELECT People.*, Pets.Title
FROM People
LEFT JOIN Pets ON People.Last_Name = Pets.Owner
Now you're getting the records you want, but not specifically the data you want. The Title
column is showing any value, and you only want it to show "Cat"
or NULL
. You can adjust the JOIN
to achieve that:
SELECT People.*, Pets.Title
FROM People
LEFT JOIN Pets ON People.Last_Name = Pets.Owner
AND Pets.Species = 'Cat'
This will filter the joined table, but not the entire result set.
Upvotes: 1