Приложение 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. 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  1001
5. 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  1001
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   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);

Глава 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)));

Глава 19

1. 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,

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);
   Шаг 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; {основной программы}
Hosted by uCoz