Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
М. ГРУБЕР_SQL.doc
Скачиваний:
22
Добавлен:
18.04.2019
Размер:
1.4 Mб
Скачать

Глава 21

#1 — не модифицируемый, потому что он использует DISTINCT.

#2 — не модифицируемый, потому что он использует объединение, агрегатную функцию и GROUP BY.

#3 — не модифицируемый, потому что он основывается на #1, который сам по себе не модифицируемый.

CREATE VIEW Commissions AS SELECT snum, comm FROM Salespeople WHERE comm BETWEEN .10 AND .20 WITH CHECK OPTION;

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

GRANT UPDATE (rating) ON Customers TO Janet;

GRANT SELECT ON Orders TO Stephen WITH GRANT OPTION;

REVOKE INSERT ON Salespeople FROM Claire;

Шаг 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;

Шаг 1:

CREATE VIEW Janetsview AS SELECT * FROM Customers WHERE rating = (SELECT MIN (rating) FROM Customers);

Шаг 2:

GRANT SELECT ON Janetsview TO Janet;

Глава 23

CREATE DBSPACE Myspace (pctindex 15, pctfree 40);

CREATE SYNONYM Orders FOR Diane.Orders;

Они должны быть откатаны обратно назад

Блокировка взаимоисключающего доступа

Только чтение

Глава 24

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 в вышеупомянутой команде — строго обязательны. Они представлены просто для понимания.

SELECT tname, synowner, COUNT (ALL synonym) FROM SYTEMSYNONS GROUP BY tname, synowner;

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

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 = 0 do { Цикл до тех пор, пока Wrong_Orders не опустеет } begin EXEC SQL FETCH Wrong_Orders INTO (:cnum, :snum); if SQLCODE = 0 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; { основная программа }

Для данной программы, которую я использовал, решение будет состоять в том, чтобы просто включить поле onum первичным ключом таблицы Заказов, в курсор Wrong_Orders. В команде UPDATE вы будете затем использовать предикат WHERE onum =:ordernum (считая целую переменную ordernum объявленной), вместо 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 = 0 do {Цикл до тех пор пока Wrong_Orders не опустеет} begin EXEC SQL FETCH Wrong_Orders INTO (:odernum, :cnum, :snum); if SQLCODE = 0 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; { основная программа } 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 = 0 do { Пока эти строки в таблице Продавцов. } begin if i_com < 0 then commnull: = true; if i_cit < 0 then citynull: = true; { Установить логические флаги, которые могут показать NULLS.} if citynull then begin write ('Нет текущего значения city для продавца ', snum, ' Хотите предоставить хотя бы одно? (Y/N)'); { Подсказка покажет значение city состоящее из NULL значений. } read (response); { Ответ может быть сделан позже. } end { если citynull } else begin { не citynull } 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)'); { Обратите Внимание: Продавец, не назначеный в данное время в определенный город, не будет иметь изменений комиссионых при определении, находятся ли он в Лондоне. } read (response); { Ответ теперь имеет значение независимо от того, что 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; {основной программы}

Приложение B