Vous êtes sur la page 1sur 10

Lsningsforslag

uke 10
INF212 - Vren 2002

Jrgen Hermanrud Fjeld <jorgenhf@i.uio.no>


with precious assistance from
Marte Arnestad
Harald Askestad
Kai-Robert Bjrnstad
Tor Even Ramberg
8. mars 2002
6.1.4

a
SELECT class, country
FROM Classes
WHERE numGuns >= 10;

b
SELECT name AS shipName
FROM Ships
WHERE launched < '1918' ;

c
SELECT ship, battle
FROM Outcomes
WHERE result = 'sunk' ;

d
SELECT ship
FROM Ships
WHERE name = class;

e
SELECT name
FROM Ships
WHERE name LIKE 'R%';

f
We presume that there are no consecutive spaces in the names, and we ignore
the possibility of ships mentioned in Outcomes, but not present in the Ships
relation. This is because this task would not be doable with the limited set
of SQL that is taught in this chapter.

SELECT name
FROM Ships
WHERE name LIKE '% % %';
6.2.3

a
SELECT S.name
FROM Ships AS S, Classes as C
WHERE S.class = C.class AND
C.displacement > 35000;

b
SELECT S.name, C.displacement, C.numGuns
FROM Outcomes AS O, Classes AS C, Ships AS S
WHERE O.battle = 'Guadalcanal' AND
C.class = S.class AND
O.ship = S.name;

c
( SELECT name AS ship FROM Ships )
UNION
( SELECT ship FROM Outcomes );
If we assume that each and every class is named so after the rst ship in that
class, we have that Classes implicitly names ships.

( SELECT name AS ship FROM Ships )


UNION
( SELECT ship FROM Outcomes )
UNION
( SELECT class AS ship FROM Classes );
The exercise isn't clear on wether or not this is the case!

d
( SELECT country FROM Classes WHERE type = 'bb' )
INTERSECT
( SELECT country FROM Classes WHERE type = 'bc' );
or equivalently

SELECT C1.country
FROM Classes AS C1, Classes as C2
WHERE C1.type = 'bb' AND
C2.type = 'bc' AND
C1.country = C2.country ;

e
SELECT O1.ship
FROM Outcomes AS O1, Outcomes AS O2, Battles AS B1, Battles AS B2
WHERE O1.ship = O2.ship AND
O1. result = 'damaged' AND
B1.name = O1.battle AND
B2.name = O2.battle AND
B1.date < B2.date ;

f
SELECT B1.battle AS battle
FROM Classes AS C1, Classes AS C2, Classes AS C3
Ships AS S1, Ships AS S2, Ships AS S3,
Outcomes AS O1, Outcomes AS O2, Outcomes AS O3
WHERE C1.country = C2.country AND
C2.country = C3.country AND
C1.class = S1.class AND
C2.class = S2.class AND
C3.class = S3.class AND
S1.name = O1.ship AND
S2.name = O2.ship AND
S3.name = O3.ship AND
O1.battle = O2.battle AND
O2.battle = O3.battle AND
O1.ship <> O2.ship AND
O2.ship <> O3.ship AND
O1.ship <> O3.ship ;
This is not an easy query to read, but if we look ahead and use more advanced
SQL, it becomes much simpler

SELECT battle
FROM Outcomes, Ships, Classes
WHERE ship=name AND
Ship.class = Class.class
GROUP BY battle, country
HAVING count(*) >= 3;
or, even prettier ;-)

SELECT battle
FROM ( ( Ships NATURAL JOIN Classes ) JOIN Outcomes ON ship=name )
GROUP BY battle, country
HAVING count(*) >= 3;
Note that we need to group by both battle and country, because we want
to consider three ships from each and every country within each and every
battle.

6.2.4
The relational-agebra query

L (C (R1 xR2 x : : : xRn )) can be written as

SELECT L
FROM R1, R2, ... , Rn
WHERE C;
6.3.2

a
SELECT country
FROM Classes
WHERE numGuns >= ALL ( SELECT numGuns FROM Classes) ;
SELECT country
FROM Classes
WHERE NOT numGuns < ANY ( SELECT numGuns FROM Classes) ;
SELECT country
FROM Classes as C1
WHERE NOT EXISTS( SELECT *
FROM Classes AS C2
WHERE C1.numGuns < C2.numGuns ) ;
SELECT country
FROM Classes
WHERE numGuns IN ( SELECT MAX(numGuns)
FROM Classes ) ;

b
SELECT class
FROM Ships
WHERE name IN ( SELECT ship
FROM Outcomes
WHERE result = 'sunk' );
SELECT class
FROM Ships
5

WHERE name = ANY ( SELECT ship


FROM Outcomes
WHERE result = 'sunk' );
SELECT class
FROM Ships AS S
WHERE EXISTS ( SELECT *
FROM Outcomes
WHERE result = 'sunk' AND
S.name = ship ) ;

c
SELECT name
FROM Ships
WHERE class IN ( SELECT class
FROM Classes
WHERE bore = 16 );
SELECT S.name
FROM Ships AS S
WHERE EXISTS ( SELECT *
FROM Classes as C
WHERE C.class = S.class AND
C.bore = 16 ) ;
And resultvise same, but simpler

SELECT name
FROM ( Classes NATURAL JOIN Ships )
WHERE bore = 16 ;

d
SELECT battle
FROM Outcomes
WHERE ship IN ( SELECT name
FROM Ships
WHERE class = 'Kongo' ) ;
SELECT O.battle
6

FROM Outcomes as O
WHERE EXISTS ( SELECT *
FROM Ships AS S
WHERE S.class = 'Kongo' AND
S.name = O.ship );

e
SELECT S.name
FROM ( Ships NATURAL JOIN Classes ) AS S
WHERE numGuns >= ALL ( SELECT numGuns
FROM Classes AS C
WHERE C.bore = S.bore );
SELECT S.name
FROM Ships AS S
WHERE EXISTS ( SELECT *
FROM Classes AS C
WHERE C.class = S.class AND
NOT C.numGuns < ANY ( SELECT C1.numGuns
FROM Classes AS C1
WHERE C1.bore = C.bore ) );
6.3.9
If we assume that there might be ships who's class isn't mentioned in the
Classes relation, we have

SELECT *
FROM Ships NATURAL LEFT OUTER JOIN Classes ;
If assume all ship's classes are in Classes, we get

SELECT *
FROM Ships s, Classes c
WHERE s.class = c.class ;
or

SELECT *
FROM Ships NATURAL JOIN Classes ;

6.3.10
If we allow name to be a NULL value, which isn't very reasonable, but
possible. Thus we get:

SELECT * FROM Ships NATURAL OUTER JOIN Classes;


Else we must take All the Ships, and the Classes information that is available
and UNION that with the Classes that doesn't have a ship in relation Ships,
thus we insert NULL for missing data and rename class as name:

( SELECT name, class, launched,


type, country, numGuns, bore, displacement
FROM Ships NATURAL LEFT OUTER JOIN Classes )
UNION
( SELECT class AS name, class, NULL AS launched,
type, country, numGuns, bore, displacement
FROM Classes AS C
WHERE NOT EXISTS ( SELECT *
FROM Ships AS S
WHERE S.class = C.class ) );
6.4.7

a
SELECT COUNT(*) AS numOfBattleshipClasses
FROM Classes
WHERE type = 'bb';

b
SELECT AVG(numGuns) AS meanNumGuns
FROM Classes
WHERE type = 'bb' ;

c
For this to be dierent from the previous, we must weigth a class by the
number of ships. We leave out classes without ships.

SELECT AVG(numGuns) AS meanNumGuns


FROM ( Ships INNER NATURAL JOIN Classes )
WHERE type = 'bb'
or equivalently

SELECT AVG(numGuns)
FROM Classes c, Ships s
WHERE c.class = s.class AND
c.type = 'bb' ;

d
SELECT class, MIN(launched)
FROM Ships
GROUP BY class;

e
SELECT class, COUNT(ship) AS shipCount
FROM ( Ships LEFT OUTER JOIN Outcomes ON name = ship )
WHERE result = 'sunk'
GROUP BY class;

f
Almost same as previous, but only allow classes with 3 or more ships, but
note how this is done. We rst get all classes that have more than three
ships, by the class IN statement that appears in the WHERE, then we
lter on those that actually sunk. This kind of subselect is necessary because
the ltering on number of ships in a class only can appear in the HAVING
clause.

SELECT class, COUNT(ship) AS shipCount


FROM ( Ships LEFT OUTER JOIN Outcomes AS ON name = ship )
WHERE result = 'sunk' AND
class IN ( SELECT class
FROM Ships
GROUP BY class
HAVING count(ship) >= 3 )
GROUP BY class;

g
SELECT country, AVG((bore*bore*bore)/2) AS meanShellWeight
FROM ( Ships INNER NATURAL JOIN Classes )
GROUP BY country;

10

Vous aimerez peut-être aussi