1. cnum2. rating3. Другим названием строки является "запись". Другим названием столбца
является "поле".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 10015. 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 10016. 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 10073. 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)));
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. Обратите Внимание: Продавец, не назначенный в данное время
в определенный город, не будет иметь изменений комиссионных
при определении того, находится ли он в Лондоне.
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; {основной программы}