Приложение A

ОТВЕТЫ ДЛЯ УПРАЖНЕНИЙ

Глава 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. onumamtodate cnumsnum

 300118.6910/03/199020081007

 3003 767.1910/03/199020011001

 30055160.4510/03/199020031002

 30091713.2310/04/199020021003

 300775.7510/04/199020041002

 30084723.0010/05/199020061001

 30101309.9510/06/199020041002

 30119891.8810/06/199020061001
5. onum amtodate 	cnumsnum
 
 300118.6910/03/199020081007
 
 3003767.19 10/03/199020011001


onumamtodatecnumsnum

30061098.1610/03/1990 20081007

30091713.2310/04/1990 20021003

300775.7510/04/1990 20041002

30084723.0010/05/1990 20061001

30101309.9510/06/1990 20041002

30119891.8810/06/1990 20061001
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 GiovanniRome200 1003

 2003 Liu San Jose200 1002

 2004 Grass Berlin300 1002

 2008 CisnerosSanJose 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,
cnamechar(10),
citychar(10),
ratinginteger,
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,
amtdecimal,
odatedate NOT NULL,
cnuminteger NOT NULL,
snuminteger NOT NULL,
UNIOUE (snum, cnum));

или

CREATE TABLE Orders
(onum integer NOT NULL UNIQUE,
amtdecimal,
odatedate NOT NULL,
cnuminteger NOT NULL,
snuminteger NOT NULL,
UNIQUE (snum, cnum));

Первое решение предпочтительнее.
2. CREATE TABLE Salespeople
(snum integer NOT NULL PRIMARY KEY,
snamechar(15) CHECK (sname BETWEEN 'AA' AND 'MZ'),
citychar(15),
commdecimal NOT NULL DEFAULT = .10);
3.CREATE TABLE Orders
(onum integer NOT NULL,
amtdecimal,
odatedate,
cnuminteger NOT NULL,
snuminteger NOT NULL,
CHECK ((cnum > snum) AND (onum > cnum)));
Глава 19
1. CREATE TABLE Cityorders
(onum integer NOT NULL PRIMARY KEY,
amtdecimal,
cnuminteger,
snuminteger,
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,
amtdecimal,
odatedate,
cnuminteger NOT NULL,
snuminteger,
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;
 odernuminteger;
 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;
SQLCODEinteger;
newcitypacked array[1. .12] of char;
commnullboolean;
citynull boolean;
responsechar;

 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.Обратите Внимание: Продавец, не назначенный в данное время
в определенный город, не будет иметь изменений комиссионных
при определении того, находится ли он в Лондоне.

read (ответ);

{Ответ теперь имеет значение, независимо от того, верен или неверен citynull.}

end; {иначе не citynull}
if response = 'Y' then
begin
write ('Введите новое значение city:');
read (newcity);
if not commnull then

{Эта операция может быть выполнена только для не-NULL значений.}

case newcity of:
 begin
'Barcelona':comm:= comm + .01,
'San Jose': comm: = comm *.01
 end; {случно и если не commnull}
EXEC SQL UPDATE Salespeople
 SET city = :newcity, comm = :comm:i_com
 WHERE CURRENT OF Salesperson;

{Переменная индикатора может поместить NULL-значение в поле comm, если так назначено.}

 end; {Если ответ = 'Y' или если ответ < > 'Y', изменений не будет.}

 EXEC SQL FETCH Salesperson
INTO (:snum, :sname, :city:i_clt,
 :comm:l_com);

{выборка следующей строки}

 end; {если SQLCODE = 0}
 EXEC SQL CLOSE CURSOR Salesperson;
 end; {основной программы}