Queries
Queries
Queries
txt
Q17) Compute increments for the ratings of persons who have sailed two different
boats on the same day.
SELECT S.sname, S.rating+1 AS rating
FROM Sailors S, Reserves R1, Reserves R2
WHERE S.sid = R1.sid AND S.sid = R2.sid
AND R1.day = R2.day AND R1.bid <> R2.bid
Q5) Find the names of sailors who have reserved a red or a green boat.
SELECT S.sname
FROM Sailors S, Reserves R, Boats B
WHERE S.sid = R.sid AND R.bid = B.bid
AND (B.color = red OR B.color = green)
6) Find the names of sailors who have reserved both a red and a green boat.
SELECT S.sname
FROM Sailors S, Reserves R1, Boats B1, Reserves R2, Boats B2
WHERE S.sid = R1.sid AND R1.bid = B1.bid
AND S.sid = R2.sid AND R2.bid = B2.bid
AND B1.color=red AND B2.color = green
The previous query is difficult to understand (and also quite inefficient to execute,
as it turns out). In particular, the similarity to the previous OR query (Query Q5) is
completely lost. A better solution for these two queries is to use UNION and INTERSECT.
The OR query (Query Q5) can be rewritten as follows:
SELECT S.sname
FROM Sailors S, Reserves R, Boats B
WHERE S.sid = R.sid AND R.bid = B.bid AND B.color = red
UNION
SELECT S2.sname
FROM Sailors S2, Boats B2, Reserves R2
WHERE S2.sid = R2.sid AND R2.bid = B2.bid AND B2.color = green
This query says that we want the union of the set of sailors who have reserved red
boats and the set of sailors who have reserved green boats. In complete symmetry, the
AND query (Query Q6) can be rewritten as follows:
SELECT S.sname
FROM Sailors S, Reserves R, Boats B
WHERE S.sid = R.sid AND R.bid = B.bid AND B.color = red
INTERSECT
SELECT S2.sname
FROM Sailors S2, Boats B2, Reserves R2
WHERE S2.sid = R2.sid AND R2.bid = B2.bid AND B2.color = green
Subqueries are usually fine unless they are dependent subqueries (also known
as correlated subqueries). If you are only using independent subqueries and they are using
appropriate indexes then they should run quickly. If you have a dependent subquery you
might run into performance problems because a dependent subquery typically needs to be
run once for each row in the outer query. So if your outer query has 1000 rows, the
subquery will be run 1000 times. On the other hand an independent subquery typically only
needs to be evaluated once.
If you're not sure what is meant by a subquery being dependent or independent here's a
rule of thumb - if you can take the subquery, remove it from its context, run it, and get a
result set then it's an independent subquery.
If you get a syntax error because it refers to some tables outside of the subquery then its
a dependent subquery.
The general rule of course has a few exceptions. For example:
Many optimizers can take a dependent subquery and find a way to run it efficiently
as a JOIN. For example an NOT EXISTS query might result in an ANTI JOIN query
plan, so it will not necessarily be any slower than writing the query with a JOIN.
We have already seen the set-comparison operators EXISTS, IN, and UNIQUE, along
with their negated versions. SQL also supports op ANY and op ALL, where op is one of
the arithmetic comparison operators {<, <=, =, <>, >=, >}. (SOME is also available,
but it is just a synonym for ANY.)
(Q22) Find sailors whose rating is better than some sailor called Horatio.
SELECT S.sid
FROM Sailors S
WHERE S.rating > ANY ( SELECT S2.rating
FROM Sailors S2
WHERE S2.sname = Horatio )
Our next example illustrates how the division operation in relational algebra can be
expressed in SQL.
(Q9) Find the names of sailors who have reserved all boats.
SELECT S.sname
FROM Sailors S
WHERE NOT EXISTS (( SELECT B.bidFROM Boats B )
EXCEPT
(SELECT R.bid
FROM Reserves R
WHERE R.sid = S.sid ))
Notice that this query is correlatedfor each sailor S, we check to see that the set of
boats reserved by S includes all boats. An alternative way to do this query without
using EXCEPT follows:
SELECT S.sname
FROM Sailors S
WHERE NOT EXISTS ( SELECT B.bid
FROM Boats B
WHERE NOT EXISTS ( SELECT R.bid
FROM Reserves R
Intuitively, for each sailor we check that there is no boat that has not been reserved
by this sailor.
(Q30) Find the names of sailors who are older than the oldest sailor with a rating of
10.
SELECT S.sname
FROM Sailors S
WHERE S.age > ( SELECT MAX ( S2.age )
FROM Sailors S2
WHERE S2.rating = 10 )
On instance S3, the oldest sailor with rating 10 is sailor 58, whose age is 35. The
names of older sailors are Bob, Dustin, Horatio, and Lubber. Using ALL, this query
could alternatively be written as follows:
SELECT S.sname
FROM Sailors S
WHERE S.age > ALL ( SELECT S2.age
FROM Sailors S2
WHERE S2.rating = 10 )
However, the ALL query is more error proneone could easily (and incorrectly!) use
ANY instead of ALL, and retrieve sailors who are older than some sailor with a rating
of 10. The use of ANY intuitively corresponds to the use of MIN, instead of MAX, in the
previous query.
SELECT [ DISTINCT ] select-list
FROM from-list
WHERE qualification
GROUP BY grouping-list
HAVING group-qualification
(Q33) For each red boat, find the number of reservations for this boat
It is interesting to observe that the following version of the above query is illegal:
SELECT B.bid, COUNT (*) AS sailorcount
FROM Boats B, Reserves R
WHERE R.bid = B.bid
GROUP BY B.bid
HAVING B.color = red
Even though the group-qualification B.color = red is single-valued per group, since
the grouping attribute bid is a key for Boats (and therefore determines color), SQL
disallows this query. Only columns that appear in the GROUP BY clause can appear in
the HAVING clause, unless they appear as arguments to an aggregate operator in the
HAVING clause.
OBSESR
Intersect
-> IN
SELECT S.sname
FROM Sailors S, Reserves R, Boats B
WHERE S.sid = R.sid AND R.bid = B.bid AND B.color = 'red'
INTERSECT
SELECT S2.sname
FROM Sailors S2, Boats B2, Reserves R2
WHERE S2.sid = R2.sid AND R2.bid = B2.bid AND B2.color= 'green';
REM Nested Query
SELECT S.sname
FROM Sailors S, Reserves R, Boats B
WHERE S.sid = R.sid AND R.bid = B.bid AND B.color ='red'
AND S.sid IN (SELECT S2.sid
FROM Sailors S2, Boats B2, Reserves R2
WHERE S2.sid = R2.sid AND R2.bid = B2.bid
AND B2.color ='green');
|_> MINUS
MINUS->NOT IN
SELECT S.sname
FROM Sailors S, Reserves R, Boats B
WHERE S.sid = R.sid AND R.bid = B.bid AND B.color = 'red'
MINUS
SELECT S2.sname
FROM Sailors S2, Boats B2, Reserves R2