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');
Могут быть и другие решения.
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);
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;
Эти вопросы могут иметь и другие, такие же хорошие решения.
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)));
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);
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; {основной программы}