|
-------------------------------------------------------------------------------- |
|
ОТВЕТЫ ДЛЯ УПРАЖНЕНИЙ |
Глава 1 |
1. cnum |
2. rating |
3. Другим названием строки является "запись". Другим названием столбца |
является "поле". |
4. Потому что строки, по определению, находятся без какого либо |
определённого упорядочивания. |
Глава 2 |
1. Символ (или текст) и число |
2. Нет |
3. Язык Манипулирования Данными (ЯЗЫК DML) |
4. Это слово в SQL имеет специальное учебное значение |
Глава 3 |
1. SELECT onum, amt, odate |
FROM Orders; |
2. SELECT * |
FROM Customers |
WHERE snum = 1001; |
3 SELECT city, sname, snum, comm |
FROM Salespeople; |
4. SELECT rating, cname |
FROM Customers |
WHERE city = 'SanJose'; |
5. SELECT DISTINCT snum |
FROM Orders; |
Глава 4 |
1. SELECT * FROM Orders WHERE amt > 1000; |
2. SELECT sname, city |
FROM Salespeople |
WHERE city = 'London' |
AND comm > .10; |
3. SELECT * |
FROM Customers |
WHERE rating > 100 |
OR city = 'Rome'; |
|
или |
|
SELECT * |
FROM Customers |
WHERE NOT rating < = 100 |
OR city = 'Rome'; |
|
или |
|
SELECT * |
FROM Customers |
WHERE NOT (rating < = 100 |
AND city < > 'Rome'); |
|
Могут быть и другие решения. |
4. onum amt odate cnum snum |
|
3001 18.69 10/03/1990 2008 1007 |
|
3003 767.19 10/03/1990 2001 1001 |
|
3005 5160.45 10/03/1990 2003 1002 |
|
3009 1713.23 10/04/1990 2002 1003 |
|
3007 75.75 10/04/1990 2004 1002 |
|
3008 4723.00 10/05/1990 2006 1001 |
|
3010 1309.95 10/06/1990 2004 1002 |
|
3011 9891.88 10/06/1990 2006 1001 |
5. onum amt odate cnum snum |
|
3001 18.69 10/03/1990 2008 1007 |
|
3003 767.19 10/03/1990 2001 1001 |
|
|
onum amt odate cnum snum |
|
3006 1098.16 10/03/1990 2008 1007 |
|
3009 1713.23 10/04/1990 2002 1003 |
|
3007 75.75 10/04/1990 2004 1002 |
|
3008 4723.00 10/05/1990 2006 1001 |
|
3010 1309.95 10/06/1990 2004 1002 |
|
3011 9891.88 10/06/1990 2006 1001 |
6. SELECT * |
FROM Salespeople; |
Глава 5 |
1. SELECT * |
FROM Orders |
WHERE odate IN (10/03/1990,10/04/1990); |
|
и |
|
SELECT * |
FROM Orders |
WHERE odate BETWEEN 10/03/1990 AND 10/04,1990; |
2. SELECT * |
FROM Customers |
WHERE snum IN (1001,1004); |
3. SELECT * |
FROM Customers |
WHERE cname BETWEEN 'A' AND 'H'; |
ПРИМЕЧАНИЕ: в ASCII-базовой системе Hoffman не будет выведен из-за конечных пробелов после H. По той же самой причине вторая граница не может быть G, поскольку она не выведет имена Giovanni и Grass. G может использоваться в сопровождении Z так, чтобы следовать за другими символами в алфавитном порядке, а не предшествовать им, как это делают пробелы. |
4. SELECT * |
FROM Customers |
WHERE cname LIKE 'C%'; |
5. SELECT * |
FROM Orders |
WHERE amt < > O |
AND (amt IS NOT NULL); |
|
или |
|
SELECT * |
FROM Orders |
WHERE NOT (amt = O |
OR amt IS NULL); |
Глава 6 |
1. SELECT COUNT(*) |
FROM Orders |
WHERE odate = 10/03/1990; |
2. SELECT COUNT (DISTINCT city) |
FROM Customers; |
3. SELECT cnum, MIN (amt) |
FROM Orders |
GROUP BY cnum; |
4 SELECT MIN (cname) |
FROM Customers |
WHERE cname LIKE 'G%'; |
5. SELECT city, |
MAX (rating) |
FROM Customers |
GROUP BY city; |
6 SELECT odate, count (DISTINCT snum |
FROM Orders |
GROUP BY odate; |
Глава 7 |
1. SELECT onum, snum, amt * .12 |
FROM Orders; |
2. SELECT 'For the city ', city, ', the highest rating is ', ", |
MAX (rating) |
FROM Customers |
GROUP BY city; |
3 SELECT rating, cname, cnum |
FROM Customers |
ORDER BY rating DESC; |
4. SELECT odate, SUM (amt) |
FROM Orders |
GROUP BY odate |
ORDER BY 2 DESC; |
Глава 8 |
1. SELECT onum, cname |
FROM Orders, Customers |
WHERE Customers.cnum = Orders.cnum; |
2. SELECT onum, cname, sname |
FROM Orders, Customers, Salespeople |
WHERE Customers.cnum = Orders.cnum |
AND Salespeople.snum = Orders.snum; |
3. SELECT cname, sname, comm |
FROM Salespeople, Customers |
WHERE Salespeople.snum = Customers.snum |
AND comm * .12; |
4. SELECT onum, comm * amt |
FROM Salespeople, Orders, Customers |
WHERE rating > 100 |
AND Orders.cnum = Customers.cnum |
AND Orders.snum = Salespeople.snum; |
Глава 9 |
1. SELECT first.sname, second.sname |
FROM Salespeople first, Salespeople second |
WHERE first.city = second.city |
AND first.sname < second.sname; |
Псевдонимам не обязаны иметь именно такие имена. |
2. SELECT cname, first.onum, second.onum |
FROM Orders first, Orders second, Customers |
WHERE first.cnum = second.cnum |
AND first.cnum = Customers.cnum |
AND first.onum < second.onum; |
Ваш вывод может иметь некоторые отличия, но в вашем ответе все логические |
компоненты должны быть такими же. |
3. SELECT a.cname, a.city |
FROM Customers a, Customers b |
WHERE a.rating = b.rating |
AND b.cnum = 2001; |
Глава 10 |
1. SELECT * |
FROM Orders |
WHERE cnum = |
(SELECT cnum |
FROM Customers |
WHERE cname = 'Cisneros'); |
|
или |
|
SELECT * |
FROM Orders |
WHERE cnum IN |
(SELECT cnum |
FROM Customers |
WHERE cname = 'Cisneros'); |
2. SELECT DISTINCT cname, rating |
FROM Customers, Orders |
WHERE amt > |
(SELECT AVG (amt) |
FROM Orders) |
AND Orders.cnum = Customers.cnum; |
3 SELECT snum, SUM (amt) |
FROM Orders |
GROUP BY snum |
HAVING SUM (amt) > |
(SELECT MAX (amt) |
FROM Orders); |
Глава 11 |
1. SELECT cnum, cname |
FROM Customers outer |
WHERE rating = |
(SELECT MAX (rating) |
FROM Customers inner |
WHERE inner.city = outer.city); |
2. Решение с помощью соотнесенного подзапроса: |
SELECT snum, sname |
FROM Salespeople main |
WHERE city IN |
(SELECT city |
FROM Customers inner |
WHERE inner.snum < > main.snum); |
|
Решение с помощью объединения: |
|
SELECT DISTINCT first.snum, sname |
FROM Salespeople first, Customers second |
WHERE first.city = second.city |
AND first.snum < > second.snum; |
Соотнесенный подзапрос находит всех заказчиков, не обслуживаемых данным продавцом, и выясняет: живёт ли кто-нибудь из их в его городе. Решение с помощью объединения является более простым и более интуитивным. Оно находит случаи, где поля city совпадают, а поля snums - нет. Следовательно, объединение является более изящным решением для этой проблемы, чем то, которое мы исследовали до этого. Имеется ещё более изящное решение с помощью подзапроса, с которым Вы столкнетесь позже. |
Глава 12 |
1. SELECT * |
FROM Salespeople first |
WHERE EXISTS |
(SELECT * |
FROM Customers second |
WHERE first.snum = second.snum |
AND rating = 300); |
2. SELECT a.snum, sname, a.city, comm |
FROM Salespeople a, Customers b |
WHERE a.snum = b.snum |
AND b.rating = 300; |
3. SELECT * |
FROM Salespeople a |
WHERE EXISTS |
(SELECT * |
FROM Customers b |
WHERE b.city = a.city |
AND a.snum < > b.snum); |
4. SELECT * |
FROM Customers a |
WHERE EXISTS |
(SELECT * |
FROM Orders b |
WHERE a.snum = b.snum |
AND a.cnum < > b.cnum) |
Глава 13 |
1. SELECT * |
FROM Customers |
WHERE rating > = ANY |
(SELECT rating |
FROM Customers |
WHERE snum = 1002); |
2. cnum cname city rating snum |
|
2002 Giovanni Rome 200 1003 |
|
2003 Liu San Jose 200 1002 |
|
2004 Grass Berlin 300 1002 |
|
2008 Cisneros SanJose 300 1007 |
3. SELECT * |
FROM Salespeople |
WHERE city < > ALL |
(SELECT city |
FROM Customers); |
|
или |
|
SELECT * |
FROM Salespeople |
WHERE NOT city = ANY |
(SELECT city |
FROM Customers); |
4. SELECT * |
FROM Orders |
WHERE amt > ALL |
(SELECT amt |
FROM Orders a, Customers b |
WHERE a.cnum = b.cnum |
AND b.city = 'London'); |
5. SELECT * |
FROM Orders |
WHERE amt > |
(SELECT MAX (amt) |
FROM Orders a, Customers b |
WHERE a.cnum = b.cnum |
AND b.city = 'London'); |
Глава 14 |
1. SELECT cname, city, rating, 'High Rating' |
FROM Customers |
WHERE rating > = 200 |
|
UNION |
|
SELECT cname, city, rating, ' Low Ratlng' |
FROM Customers |
WHERE rating < 200; |
|
или |
|
SELECT cname, city, rating, 'High Rating' |
FROM Customers |
WHERE rating > = 200 |
|
UNION |
|
SELECT cname, city, rating, ' Low Rating' |
FROM Customers |
WHERE NOT rating > = 200; |
Различие между этими двум предложениями - в форме второго предиката. Обратите внимание, что в обоих случаях строка "Low Rating" имеет в начале дополнительный пробел, для того чтобы совпадать со строкой "High Rating" по длине. |
2. SELECT cnum, cname |
FROM Customers a |
WHERE 1 < |
(SELECT COUNT (-) |
FROM Orders b |
WHERE a.cnum = b.cnum) |
|
UNION |
|
SELECT snum, sname |
FROM Salespeople a |
WHERE 1 < |
(SELECT COUNT (*) |
FROM Orders b |
WHERE a.snum = b.snum) |
|
ORDER BY 2; |
|
3. SELECT snum |
FROM Salespeople |
WHERE city = 'San Jose' |
|
UNION |
|
(SELECT cnum |
FROM Customers |
WHERE city = 'San Jose' |
|
UNION ALL |
|
SELECT onum |
FROM Orders |
WHERE odate = 10/03/1990); |
Глава 15 |
1. INSERT INTO Salespeople (city, cname, comm, cnum) |
VALUES ('San Jose', 'Blanco', NULL, 1100); |
2. DELETE FROM Orders WHERE cnum = 2006; |
3. UPDATE Customers |
SET rating = rating + 100 |
WHERE city = 'Rome'; |
4. UPDATE Customers |
SET snum = 1004 |
WHERE snum = 1002; |
Глава 16 |
1. INSERT INTO Multicust |
SELECT * |
FROM Salespeople |
WHERE 1 < |
(SELECT COUNT (*) |
FROM Customers |
WHERE Customers.snum = Salespeople.snum); |
2. DELETE FROM Customers |
WHERE NOT EXISTS |
(SELECT * |
FROM Orders |
WHERE cnum = Customers.cnum); |
3. UPDATE Salespeople |
SET comm = comm + (comm * .2) |
WHERE 3000 < |
(SELECT SUM (amt) |
FROM Orders |
WHERE snum = Salespeople.snum); |
В более сложный вариант этой команды можно было бы вставить проверку, чтобы убедиться, что значения комиссионных не превышают 1.0 (100 %): |
UPDATE Salespeople |
SET comm = comm + (comm * .2) |
WHERE 3000 < |
(SELECT SUM (amt) |
FROM Orders |
WHERE snum = Salespeople.snum) |
AND comm + (comm * .2) < 1.0; |
Эти вопросы могут иметь и другие, такие же хорошие решения. |
Глава 17 |
1. CREATE TABLE Customers |
(cnum integer, |
cname char(10), |
city char(10), |
rating integer, |
snum integer); |
2. CREATE INDEX Datesearch ON Orders(odate); |
|
(Все индексные имена, используемые в этих ответах - произвольные.) |
3. CREATE UNIQUE INDEX Onumkey ON Orders(onum); |
4. CREATE INDEX Mydate ON Orders(snum, odate); |
5. CREATE UNIQUE INDEX Combination ON |
Customers(snum, rating); |
Глава 18 |
1. CREATE TABLE Orders |
(onum integer NOT NULL PRIMARY KEY, |
amt decimal, |
odate date NOT NULL, |
cnum integer NOT NULL, |
snum integer NOT NULL, |
UNIOUE (snum, cnum)); |
|
или |
|
CREATE TABLE Orders |
(onum integer NOT NULL UNIQUE, |
amt decimal, |
odate date NOT NULL, |
cnum integer NOT NULL, |
snum integer NOT NULL, |
UNIQUE (snum, cnum)); |
|
Первое решение предпочтительнее. |
2. CREATE TABLE Salespeople |
(snum integer NOT NULL PRIMARY KEY, |
sname char(15) CHECK (sname BETWEEN 'AA' AND 'MZ'), |
city char(15), |
comm decimal NOT NULL DEFAULT = .10); |
3. CREATE TABLE Orders |
(onum integer NOT NULL, |
amt decimal, |
odate date, |
cnum integer NOT NULL, |
snum integer NOT NULL, |
CHECK ((cnum > snum) AND (onum > cnum))); |
Глава 19 |
1. CREATE TABLE Cityorders |
(onum integer NOT NULL PRIMARY KEY, |
amt decimal, |
cnum integer, |
snum integer, |
city char (15), |
FOREIGN KEY (onum, amt, snum) |
REFERENCES Orders (onum, amt, snum), |
FOREIGN KEY (cnum, city) |
REFERENCES Customers (cnum, city)); |
2. CREATE TABLE Orders |
(onum integer NOT NULL, |
amt decimal, |
odate date, |
cnum integer NOT NULL, |
snum integer, |
prev integer, |
UNIQUE (cnum, onum), |
FOREIGN KEY (cnum, prev) REFERENCES Orders (cnum,onum));9 |
Глава 20 |
1. CREATE VIEW Highratings |
AS SELECT * |
FROM Customers |
WHERE rating = |
(SELECT MAX (rating) |
FROM Customers); |
2. CREATE VIEW Citynumber |
AS SELECT city, COUNT (DISTINCT snum) |
FROM Salespeople |
GROUP BY city; |
3. CREATE VIEW Nameorders |
AS SELECT sname, AVG (amt), SUM (amt) |
FROM Salespeople, Orders |
WHERE Salespeople.snum = Orders.snum |
GROUP BY sname; |
4 CREATE VIEW Multcustomers |
AS SELECT * |
FROM Salespeople a |
WHERE 1 < |
(SELECT COUNT (*) |
FROM Customers b |
WHERE a.snum = b.snum); |
Глава 21 |
1. #1 - не модифицируемый, потому что он использует DISTINCT. |
#2 - не модифицируемый, потому что он использует объединение, |
агрегатную функцию и GROUP BY. |
#3 - не модифицируемый, потому что он основывается на #1, который |
сам по себе немодифицируем. |
2. CREATE VIEW Commissions |
AS SELECT snum, comm |
FROM Salespeople |
WHERE comm BETWEEN .10 AND .20 |
WITH CHECK OPTION; |
3 CREATE TABLE Orders |
(onum integer NOT NULL PRIMARY KEY, |
amt decimal, |
odate date DEFAULT VALUE = CURDATE, |
snum integer, |
cnum integer); |
CREATE VIEW Entryorders |
AS SELECT onum, amt, snum, cnum |
FROM Orders; |
Глава 22 |
1. GRANT UPDATE (rating) ON Customers TO Janet; |
2. GRANT SELECT ON Orders TO Stephen WITH GRANT OPTION; |
3. REVOKE INSERT ON Salespeople FROM Claire; |
4. Шаг 1: CREATE VIEW Jerrysview |
AS SELECT * |
FROM Customers |
WHERE rating BETWEEN 100 AND 500 |
WITH CHECK OPTION; |
Шаг 2: GRANT INSERT, UPDATE ON Jerrysview TO Jerry; |
5. Шаг 1: CREATE VIEW Janetsview |
AS SELECT * |
FROM Customers |
WHERE rating = |
(SELECT MIN (rating) |
FROM Customers); |
Шаг 2: GRANT SELECT ON Janetsview TO Janet; |
Глава 23 |
1. CREATE DBSPACE Myspace |
(pctindex 15, |
pctfree 40); |
2. CREATE SYNONYM Orders FOR Diane.Orders; |
3. Они должны быть откатаны назад. |
4. Блокировка взаимоисключающего доступа. |
5. Только чтение. |
Глава 24 |
1. SELECT a.tname, a.owner, b.cname, b.datatype |
FROM SYSTEMCATOLOG a, SYSTEMCOLUMNS b |
WHERE a.tname = b.tname |
AND a.owner = b.owner |
AND a.numcolumns > 4; |
Обратите Внимание: из-за того что большинство имён столбца объединяемых таблиц различны, не все из используемых псевдонимов a и b в вышеупомянутой команде строго обязательны. Они представлены просто для понимания. |
2. SELECT tname, synowner, COUNT (ALL synonym) |
FROM SYTEMSYNONS |
GROUP BY tname, synowner; |
3 SELECT COUNT (*) |
FROM SYSTEMCATALOG a |
WHERE numcolumns/2 < |
(SELECT COUNT (DISTINCT cnumber) |
FROM SYSTEMINDEXES b |
WHERE a.owner = b.tabowner |
AND a.tname = b.tname); |
Глава 25 |
1. EXEC SQL BEGIN DECLARE SECTION; |
SQLCODE:integer; |
{требуемый всегда} |
cnum integer; |
snum integer; |
custnum: integer; |
salesnum: integer; |
EXEC SQL END DECLARE SECTION; |
EXEC SQL DECLARE Wrong_Orders AS CURSOR FOR |
SELECT cnum, snum |
FROM Orders a |
WHERE snum < > |
(SELECT snum |
FROM Customers b |
WHERE a.cnum = b.cnum); |
Мы пока ещё используем здесь SQL для выполнения основной работы. Запрос выше размещает строки таблицы Заказов, которые не согласуются с таблицей Заказчиков. |
EXEC SQL DECLARE Cust_assigns AS CURSOR FOR |
SELECT cnum, snum |
FROM Customers; |
{Этот курсор используется для получения правильных значений snum} |
begin { основная программа } |
EXEC SQL OPEN CURSOR Wrong_Orders; |
while SQLCODE = O do |
{Цикл до тех пор, пока Wrong_Orders не опустеет} |
begin |
EXEC SQL FETCH Wrong_Orders INTO |
(:cnum, :snum); |
if SQLCODE = O then |
begin |
{Когда Wrong_Orders опустеет, мы не хотели бы продолжать выполнение этого цикла до бесконечности} |
EXEC SQL OPEN CURSOR Cust_Assigns; |
repeat |
EXEC SQL FETCH Cust_Assigns |
INTO (:custnum, :salesnum); |
until :custnum = :cnum; |
|
{Повторять FETCH до тех пор, пока ... команда будет просматривать Cust_Assigns курсор до строки, которая соответствует текущему значению cnum, найденного в Wrong_Orders} |
EXEC SQL CLOSE CURSOR Cust_assigns; |
{Поэтому мы будем начинать новый вывод в следующий раз через цикл. Значение, которое мы получим из этого курсора, сохраняется в переменной salesnum.} |
EXEC SQL UPDATE Orders |
SET snum = :salesnum |
WHERE CURRENT OF Wrong_Orders; |
end; {Если SQLCODE = 0}. |
end; |
{Пока SQLCODE . . . выполнить} |
EXEC SQL CLOSE CURSOR Wrong_Orders; |
end; {основная программа} |
2. |
Для данной программы решение будет состоять в том, чтобы просто включить поле onum первичным ключом таблицы Заказов в курсор Wrong_Orders. В команде UPDATE вы будете затем использовать предикат WHERE onum =:ordernum (считая целую переменную odernum объявленной), вместо WHERE CURRENT Of Wrong_Orders. Результатом будет программа наподобие этой (большинство комментариев из предыдущей программы здесь исключены): |
EXEC SQL BEGIN DECLARE SECTION; |
SQLCODE: integer; |
odernum integer; |
cnum integer; |
snum integer; |
custnum: integer; |
salesnum: integer; |
EXEC SQL END DECLARE SECTION; |
EXEC SQL DECLARE Wrong_Orders AS CURSOR FOR |
SELECT onum, cnum, snum |
FROM Orders a |
WHERE snum < > |
(SELECT snum |
FROM Customers b |
WHERE a.cnum = b.cnum); |
EXEC SQL DECLARE Cust _ assigns AS CURSOR FOR |
SELECT cnum, snum |
FROM Customers; |
begin { основная программа } |
EXEC SQL OPEN CURSOR Wrong_Orders; |
while SQLCODE = O do {Цикл до тех пор пока Wrong_Orders |
не опустеет} |
begin |
EXEC SQL FETCH Wrong_Orders |
INTO (:odernum, :cnum, :snum); |
if SQLCODE = O then |
begin |
EXEC SQL OPEN CURSOR Cust_Assigns; |
repeat |
EXEC SQL FETCH Cust_Assigns |
INTO (:custnum, :salesnum); |
until :custnum = :cnum; |
|
EXEC SQL CLOSE CURSOR Cust_assigns; |
EXEC SQL UPDATE Orders |
SET snum = :salesnum |
WHERE CURRENT OF Wrong_Orders; |
end; {If SQLCODE = 0} |
end; { While SQLCODE . . . do } |
EXEC SQL CLOSE CURSOR Wrong_Orders; |
end; { main program } |
3. EXEC SQL BEGIN DECLARE SECTION; |
SQLCODE integer; |
newcity packed array[1. .12] of char; |
commnull boolean; |
citynull boolean; |
response char; |
|
EXEC SQL END DECLARE SECTION; |
EXEC SQL DECLARE CURSOR Salesperson AS |
SELECT * FROM SALESPEOPLE; |
begln { main program } |
EXEC SQL OPEN CURSOR Salesperson; |
EXEC SQL FETCH Salesperson |
INTO (:snum, :sname, :city:i_cit, :comm:i_com); |
|
{Выборка первой строки} |
while SQLCODE = O do |
{Пока эти строки в таблице Продавцов.} |
begin |
if i_com < O then commnull: = true; |
if i_cit < O then citynull: = true; |
{Установить логические флаги, которые могут показать NULLS.} |
|
if citynull then |
begin |
write ('Нет текущего значения city для продавца ', |
snum, ' Хотите предоставить хотя бы одно? (Y/N)'); |
|
{Подсказка покажет значение city, состоящее из NULL-значений.} |
|
read (ответ); |
|
{Ответ может быть сделан позже.} |
|
end {если конечно - citynull} |
|
else { не citynull } |
begin |
if not commnull then |
|
{Чтобы выполнять сравнение и операции только для не-NULL значений связи} |
begin |
if city = 'London' then comm: = comm * .02 * .02 |
else comm: = comm + .02; |
end; |
{Даже если значение и не commnull, begin и end здесь для ясности.} |
|
write ('Текущий city для продавца', |
snum, 'есть', city, |
Хотите его изменить? (Y/N)'); |
3. Обратите Внимание: Продавец, не назначенный в данное время |
в определенный город, не будет иметь изменений комисс
|