Мартин Грубер - Понимание SQL (991940), страница 50
Текст из файла (страница 50)
Обратите внимание, что в обоих случаях строка "Low Rating" имеет в начале дополнительный пробел для того, чтобы совпадать со строкой "High Rating" по длине.2.SELECT cnum, cnameFROM Customers aWHERE 1 < (SELECT COUNT (*)FROM Orders bWHERE a.cnum = b.cnum)UNIONSELECT snum, snameFROM Salespeople aWHERE 1 < (SELECT COUNT (*)FROM Orders bWHERE a.snum = b.snum)ORDER BY 2;3.SELECT snumFROM SalespeopleWHERE city = 'San Jose'UNION(SELECT cnumFROM CustomersWHERE city = 'San Jose'UNION ALLSELECT onumFROM OrdersWHERE odate = 10/03/1990);Глава 151.INSERT INTO Salespeople (city, cname, comm, cnum)VALUES ('San Jose', 'Blanco', NULL, 1100);2.DELETE FROM Orders WHERE cnum = 2006;3.UPDATE CustomersSET rating = rating + 100WHERE city = 'Rome';4.UPDATE CustomersSET snum = 1004WHERE snum = 1002;Глава 161.INSERT INTO MulticustSELECT *FROM SalespeopleWHERE 1 < (SELECT COUNT (*)FROM CustomersWHERE Customers.snum = Salespeople.snum);2.DELETE FROM CustomersWHERE NOT EXISTS (SELECT *FROM OrdersWHERE cnum = Customers.cnum);3.UPDATE SalespeopleSET comm = comm + (comm * .2)WHERE 3000 < (SELECT SUM (amt)FROM OrdersWHERE snum = Salespeople.snum);В более сложный вариант этой команды можно было бы вставить проверку, чтобыубедиться, что значения комиссионных не превышают 1.0 (100%):UPDATE SalespeopleSET comm = comm + (comm * .2)WHERE 3000 < (SELECT SUM (amt)FROM OrdersWHERE snum = Salespeople.snum)AND comm + (comm * .2) < 1.0;Эти проблемы могут иметь другие, такие же хорошие решения.Глава 171.CREATE TABLE Customers(cnuminteger,cname char(10),citychar(10),rating integer,snuminteger);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);Глава 181.CREATE TABLE Orders(onum integer NOT NULL PRIMARY KEY,amtdecimal,odate date NOT NULL,cnum integer NOT NULL,snum integer NOT NULL,UNIOUE (snum, cnum));илиCREATE TABLE Orders(onum integer NOT NULL UNIQUE,amtdecimal,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,amtdecimal,odate date,cnum integer NOT NULL,snum integer NOT NULL,CHECK ((cnum > snum) AND (onum > cnum)));Глава 191.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,amtdecimal,odate date,cnum integer NOT NULL,snum integer,prev integer,UNIQUE (cnum, onum),FOREIGN KEY (cnum, prev) REFERENCES Orders (cnum,onum));Глава 201.CREATE VIEW HighratingsAS SELECT *FROM CustomersWHERE rating = (SELECT MAX (rating)FROM Customers);2.CREATE VIEW CitynumberAS SELECT city, COUNT (DISTINCT snum)FROM SalespeopleGROUP BY city;3.CREATE VIEW NameordersAS SELECT sname, AVG (amt), SUM (amt)FROM Salespeople, OrdersWHERE Salespeople.snum = Orders.snumGROUP BY sname;4.CREATE VIEW MultcustomersAS SELECT *FROM Salespeople aWHERE 1 < (SELECT COUNT (*)FROM Customers bWHERE a.snum = b.snum);Глава 211.#1 — не модифицируемый, потому что он использует DISTINCT.#2 — не модифицируемый, потому что он использует обьединение, агрегатную функцию и GROUP BY.#3 — не модифицируемый, потому что он основывается на #1, который сам по себене модифицируемый.2.CREATE VIEW CommissionsAS SELECT snum, commFROM SalespeopleWHERE comm BETWEEN .10 AND .20WITH CHECK OPTION;3.CREATE TABLE Orders(onum integer NOT NULL PRIMARY KEY,amtdecimal,odate date DEFAULT VALUE = CURDATE,snum integer,cnum integer);CREATE VIEW EntryordersAS SELECT onum, amt, snum, cnumFROM Orders;Глава 221.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 JerrysviewAS SELECT *FROM CustomersWHERE rating BETWEEN 100 AND 500WITH CHECK OPTION;Шаг 2:GRANT INSERT, UPDATE ON Jerrysview TO Jerry;5.Шаг 1:CREATE VIEW JanetsviewAS SELECT *FROM CustomersWHERE rating = (SELECT MIN (rating)FROM Customers);Шаг 2:GRANT SELECT ON Janetsview TO Janet;Глава 231.CREATE DBSPACE Myspace(pctindex 15,pctfree 40);2.CREATE SYNONYM Orders FOR Diane.Orders;3.
Они должны быть откатаны обратно назад4. Блокировка взаимоисключающего доступа5. Толко чтениеГлава 241.SELECT a.tname, a.owner, b.cname, b.datatypeFROM SYSTEMCATOLOG a, SYSTEMCOLUMNS bWHERE a.tname = b.tname ANDa.owner = b.owner ANDa.numcolumns > 4;Обратите Внимание: из-за того, что большинство имен столбца объединяемых таблиц— различны, не все из используемых псевдонимов a и b в вышеупомянутой команде — строго обязательны.
Они представлены просто для понимания.2.SELECT tname, synowner, COUNT (ALL synonym)FROM SYTEMSYNONSGROUP BY tname, synowner;3.SELECT COUNT (*)FROM SYSTEMCATALOG aWHERE numcolumns/2 < (SELECT COUNT (DISTINCT cnumber)FROM SYSTEMINDEXES bWHERE a.owner = b.tabowner AND a.tname = b.tname);Глава 251.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 FORSELECT cnum, snumFROM Orders aWHERE snum <> (SELECT snumFROM Customers bWHERE a.cnum = b.cnum);{ Мы пока еще используем здесь SQL для выполнения основной работы.
Запросвыше размещает строки таблицы Порядков, которые не согласуются с таблицейЗаказчиков. }EXEC SQL DECLARE Cust_assigns AS CURSOR FORSELECT cnum, snumFROM Customers;{ Этот курсор используется для получения правильных значений snum }begin { основная программа }EXEC SQL OPEN CURSOR Wrong_Orders;while SQLCODE = 0 do { Цикл до тех пор, пока Wrong_Orders не опустеет }beginEXEC SQL FETCH Wrong_Orders INTO (:cnum, :snum);if SQLCODE = 0 thenbegin {Когда Wrong_Orders опустеет, мы не хотели бы продолжатьвыполнение этого цикла до бесконечности}EXEC SQL OPEN CURSOR Cust_Assigns;repeatEXEC 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 OrdersSET snum = :salesnumWHERE 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 FORSELECT onum, cnum, snumFROM Orders aWHERE snum <> (SELECT snumFROM Customers bWHERE a.cnum = b.cnum);EXEC SQL DECLARE Cust_assigns AS CURSOR FORSELECT cnum, snumFROM Customers;begin { основная программа }EXEC SQL OPEN CURSOR Wrong_Orders;while SQLCODE = 0 do {Цикл до тех пор пока Wrong_Orders не опустеет}beginEXEC SQL FETCH Wrong_Orders INTO (:odernum, :cnum, :snum);if SQLCODE = 0 thenbeginEXEC SQL OPEN CURSOR Cust_Assigns;repeatEXEC SQL FETCH Cust_Assigns INTO (:custnum, :salesnum);until :custnum = :cnum;EXEC SQL CLOSE CURSOR Cust_assigns;EXEC SQL UPDATE OrdersSET snum = :salesnum WHERE CURRENT OF Wrong_Orders;end; { If SQLCODE = 0 }end; { While SQLCODE ...
do }EXEC SQL CLOSE CURSOR Wrong_Orders;end; { основная программа }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 ASSELECT * 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 { Пока эти строки в таблице Продавцов.
}beginif i_com < 0 then commnull: = true;if i_cit < 0 then citynull: = true;{ Установить логические флаги, которые могут показать NULLS.}if citynullthen beginwrite ('Нет текущего значения city для продавца ', snum,' Хотите предоставить хотя бы одно? (Y/N)');{ Подсказка покажет значение city состоящее из NULL значений. }read (response);{ Ответ может быть сделан позже. }end { если citynull }else begin { не citynull }if not commnull then{ Чтобы выполнять сравнение и операции только для не-NULL значений связи }beginif city='London' then comm:=comm*.02*.02else comm:=comm+.02;end;{ Даже если значение и не - commnull, begin и end здесь для ясности.
}write ('Текущий city для продавца', snum, 'есть', city,'Хотите его изменить? (Y/N)');{ Обратите Внимание: Продавец, не назначеный в данное время в определенныйгород, не будет иметь изменений комиссионых при определении, находятся ли онв Лондоне. }read (response);{ Ответ теперь имеет значение независимо от того, что citynull верен илиневерен. }end; {иначе не citynull}if response = 'Y' thenbeginwrite ('Введите новое значение city:');read (newcity);if not commnull then{ Эта операция может быть выполнена только для не-NULL значений. }case newcity of:begin'Barcelona' : comm:= comm + .01,'San Jose' : comm:= comm * .01end; {случно и если не commnull}EXEC SQL UPDATE SalespeopleSET city = :newcity, comm = :comm:i_comWHERE CURRENT OF Salesperson;{ Переменная индикатора может поместить NULL значение в поле comm если такназначено.