CS 386/586
practice, Week 3, Fall 2011
Practice using INTERSECT, UNION, with
and without the ALL options.
Let’s look at all the skills in the Spy database:
select * from skill
Choose 2 skills:
28 Firearms
48 Pilot
Let’s find out how many people hold each skill
select skill_id, count(*) from
skillrel group by skill_id
It’s too hard to find skill 28 and 48. Try this one:
select skill_id, count(*) from skillrel group by skill_id order by
skill_id
We see that 42 agents have the skill of Firearms
We see that 43 agents have the skill of Pilot
I wonder if anyone has both skills?
Try this query:
(select agent_id from skillrel where
skill_id = 28)
intersect
(select agent_id from skillrel where
skill_id = 48)
We see 6 rows:
agent_id
30
201
316
373
540
1001
Now try this query:
(select agent_id from skillrel where
skill_id = 28)
union
(select agent_id from skillrel where
skill_id = 48)
We see 79 rows. But if we added 42 and 43, we get 85 rows. We can see that the UNION query is automatically eliminating duplicates.
Try this one:
(select agent_id from skillrel where
skill_id = 28)
union all
(select agent_id from skillrel where
skill_id = 48)
Now we see 85 rows. This is because duplicates are NOT being eliminated.
Here’s another way to see the set of agents that have a skill of Pilot, a skill of Firearms, or both, without duplicates.
Select distinct * from
((select agent_id from skillrel
where skill_id = 28)
union all
(select agent_id from skillrel where
skill_id = 48)) as f
Here, we are using a query expression in the from clause. We are using the DISTINCT clause in the SELECT Clause – to eliminate duplicates. We get 79 rows. This is the same answer we get when we take union.
Let’s find the agents_id who have a skill of Firearms but not a skill of Pilot.
(select agent_id from skillrel where
skill_id = 28)
except
(select agent_id from skillrel where
skill_id = 48)
We see 36 rows – which is 42 (the number of agents with a skill of firearms) – 6 the number of agents in the intersection.
Let’s try it the other way around.
(select agent_id from skillrel where
skill_id = 48)
except
(select agent_id from skillrel where
skill_id = 28)
We see 37 rows which is 43 (the number of agents with a skill of Pilot) minus 6 (the number of agents in the intersection).
Write a query that finds out whether any sailors reserved a red boat and also (on some other day) reserved a blue boat.
This query will show us the color of the boats in the Reserves table:
select * from reserves natural join
boats
This query will show us sailors who reserved a red boat:
select sid from reserves natural
join boats where color = 'red'
answer is:
sid
22
22
31
31
64
And this
query will show us which sailors reserved a blue boat:
select sid from reserves natural join boats where color = ‘blue’
sid
22
64
So, let’s
take the intersection of those two queries:
select
sid from reserves natural join boats where color = 'red'
intersect
select
sid from reserves natural join boats where color = 'blue'
and we
see:
sid
22
64
Suppose
we want to see the sailor’s name … for each sailor that reserved a red boat and
a blue boat. Then we need to join the
result we have so far with the sailors table.
Try
this:
(select sid, sname from sailors natural join reserves natural join
boats where color = 'red')
intersect
(select sid from reserves natural join boats where color = 'blue')
We
should get an error because these two tables are NOT union-compatible. The first one returns 2 attributes while the
second one only returns 1 attribute.
Sure
enough, we get:
SQL error:
ERROR: each INTERSECT query must have the same
number of columns
Let’s
fix the query and try it again:
(select sid, sname from sailors natural join reserves natural join
boats where color = 'red')
intersect
(select sid from reserves natural join boats where color = 'blue')
And
we get:
sid sname
22 Dustin
64 Horatio
Practice using GROUP BY and HAVING.
Let’s
find out how many reservations each boat has:
Select bid, count(*) from reserves group by bid
Bid count
102 3
101 2
104 2
103 3
Let’s find
out how many reservations each sailor has by changing the grouping attribute to
sid
Select bid, count(*) from reserves group by sid
Whoops,
we get a syntax error because we are trying to include bid in the query answer
but we are grouping on sid. Let’s fix
it:
Select sid, count(*) from reserves group by sid
We
see:
sid count
31 3
64 2
74 1
22 4
How
would you change this query to show just ids for sailors that had 2 or more
reservations?
Now,
suppose we want to see the sailor’s name as well. Here’s how we can use a subquery in the
SELECT clause … provided it returns JUST ONE value for each row in the query
answer of the original query.
select r.sid, count(*), (select sname from sailors where r.sid =
sid) from reserves r group by sid