МОДИФИЦИРОВАНИЕ ПРЕДСТАВЛЕНИЯ
Один из наиболее трудных и неоднозначных аспектов представлений -
непосредственное их использование с командами модификации DML.
Как упомянуто в предыдущей главе, эти команды фактически воздействуют на значения в базовой таблице представления.
Это является некоторым противоречием. Представление состоит из результатов запроса, и когда вы модифицируете представление, вы модифицируете набор результатов запроса. Но модификация не должна воз-
действовать на запрос ; она должна воздействовать на значения в таблице к которой был сделан запрос, и таким образом изменять вывод запроса. Это не простой вопрос. Следующий оператор будет создавать представление показанное на Рисунке 21.1:
CREATE VIEW Citymatch (custcity, salescity)
AS SELECT DISTINCT a.city, b.city
FROM Customers a, Salespeople b
WHERE a.snum = b.snum;
Это представление показывает все совпадения заказчиков с их продавца-
ми так, что имеется по крайней мере один заказчик в городе_заказчика
обслуживаемый продавцом в городе_продавца.
Например, одна строка этой таблицы - London London - показывает, что
имеется по крайней мере один заказчик в Лондоне, обслуживаемый продав-
цом в Лондоне.
Эта строка может быть произведена при совпадении Hoffmanа с его продавцом Peel, причем если оба они из Лондона.
=============== SQL Execution Log ==============
| |
| SELECT * |
| FROM Citymatch; |
| =============================================== |
| custcity salescity |
| --------- --------- |
| Berlin San Jose |
| London London |
| Rome London |
| Rome New York |
| San Jose Barselona |
| San Jose San Jose |
| |
================================================
Рисунок 21.1: Представление совпадения по городам
Однако, то же самое значение будет произведено при совпадении
Clemens из Лондона, с его продавцом, который также оказался с именем
- Peel. Пока отличающиеся комбинации городов выбирались конкретно,
только одна строка из этих значений была произведена.
Даже если вы не получите выбора используя отличи, вы все еще будете
в том же самом положении, потому что вы будете тогда иметь две строки в
представлении с идентичными значениями, то есть с обоими столбцами рав-
ными " Lоndon London ". Эти две строки представления будут отличаться
друг от друга, так что вы пока не сможете сообщить, какая строка представ-
лени исходила из каких значений базовых таблиц( имейте в виду, что запросы не использующие предложение ORDER BY, производят вывод в произвольном порядке. Это относится также и к запросам используемым внутри
представлений, которые не могут использовать ORDER BY. Таким образом,
порядок из двух строк не может быть использован для их отличий.
Это означает, что мы будем снова обращаться к выводу строк которые не мо-
гут быть точно связаны с указанными строками запрашиваемой таблицы.
Что если вы пробуете удалить строку " London London " из представления?
Означало бы это удаление Hoffmanа из таблицы Заказчиков, удаление Clemens
из той же таблицы, или удаление их обоих? Должен ли SQL также удалить
Peel из таблицы Продавцов? На эти вопросы невозможно ответить точно, по-
этому удаления не разрешены в представлениях такого типа.
Представление Citymatch - это пример представления только_чтение, оно мо-
жет быть только запрошено, но не изменено.
ЧТО ЯВЛЯЕТСЯ - МОДИФИЦИРУЕМЫМИ ПРЕДСТАВЛЕНИЕМ
Имеются некоторые примеры модифицируемых представлений и представлений только_чтение:
CREATE VIEW Dateorders (odate, ocount)
AS SELECT odate, COUNT (*)
FROM Orders
GROUP BY odate;
Это - представление только_чтение из-за присутствия в нем агрегатной
функции и GROUP BY.
CREATE VIEW Londoncust
AS SELECT *
FROM Customers
WHERE city = 'London';
А это - представление модифицируемое.
CREATE VIEW SJsales (name, number, percentage)
AS SELECT sname, snum, comm 100
FROM Salespeople
WHERE city = 'SanJose';
Это - представление только_чтение из-за выражения " comm * 100 " .
При этом, однако, возможны переупорядочение и переименование полей.
Некоторые программы будут позволять удаление в этом представлении или
в порядках столбцов snum и sname.
CREATE VIEW Salesonthird
AS SELECT *
FROM Salespeople
WHERE snum IN
(SELECT snum
FROM Orders
WHERE odate = 10/03/1990);
Это - представление только_чтение в ANSI из-за присутствия в нем
подзапроса. В некоторых программах, это может быть приемлемо.
CREATE VIEW Someorders
AS SELECT snum, onum, cnum
FROM Orders
WHERE odate IN (10/03/1990,10/05/1990);
Это - модифицируемое представление.
ПРОВЕРКА ЗНАЧЕНИЙ ПОМЕЩАЕМЫХ В ПРЕДСТАВЛЕНИЕ
Другой вывод о модифицируемости представления тот, что вы можете
вводить значения которые " проглатываются " (swallowed) в базовой
таблице. Рассмотрим такое представление:
CREATE VIEW Highratings
AS SELECT cnum, rating
FROM Customers
WHERE rating = 300;
Это - представление модифицируемое. Оно просто ограничивает ваш дос-
туп к определенным строкам и столбцам в таблице. Предположим, что вы
вставляете (INSERT) следующую строку:
INSERT INTO Highratings
VALUES (2018, 200);
Это - допустима команда INSERT в этом представлении. Строка будет
вставлена, с помощью представления Highratings, в таблицу Заказчиков.
Однако когда она появится там, она исчезнет из представления, поскольку
значение оценки не равно 300. Это - обычна проблема.
Значение 200 может быть просто напечатано, но теперь строка находится
уже в таблице Заказчиков где вы не можете даже увидеть ее. Пользователь
не сможет понять, почему введя строку он не может ее увидеть, и будет не-
способен при этом удалить ее.
Вы можете быть гарантированы от модификаций такого типа с помощью включения WITH CHECK OPTION (С ОПЦИЕЙ ПРОВЕРКИ) в определение представления. Мы можем использовать WITH CHECK OPTION в
определении представления Highratmgs.
CREATE VIEW Highratings
AS SELECT cnum, rating
FROM Customers
WHERE rating = 300
WITH CHECK OPTION;
Вышеупомянутая вставка будет отклонена.
WITH CHECK OPTION - производит действие все_или_ничего
(all-or-nothing). Вы помещаете его в определение представления, а не в
команду DML, так что или все команды модификации в представлении
будут проверяться, или ни одна не будет проверена. Обычно вы хотите
использовать опцию проверки, используя ее в определении представления, что может быть удобно.
В общем, вы должны использовать эту опцию, если у вас нет причины,
разрешать представлению помещать в таблицу значения, которые он
сам не может содержать.
ПРОВЕРКА ПРЕДСТАВЛЕНИЙ КОТОРЫЕ БАЗИРУЮТСЯ НА ДРУГИХ ПРЕДСТАВЛЕНИЯХ
Еще одно надо упомянуть относительно предложения WITH CHECK OPTION
в ANSI: оно не делает каскадированного изменения : Оно применяется только
в представлениях в которых оно определено, но не в представлениях основанных на этом представлении. Например, в предыдущем примере
CREATE VIEW Highratings
AS SELECT cnum, rating
FROM Customers
WHERE rating = 300
WITH CHECK OPTION;
попытка вставить или модифицировать значение оценки не равное 300 по-
терпит неудачу. Однако, мы можем создать второе представление ( с идентичным содержанием ) основанное на первом:
CREATE VIEW Myratings
AS SELECT *
FROM Highratings;
Теперь мы можем модифицировать оценки не равные 300:
UPDATE Myratings
SET rating = 200
WHERE cnum = 2004;
Эта команда выполняемая так как если бы она выполнялась как первое
представление, будет допустима. Предложение WITH CHECK OPTION
просто гарантирует, что люба модификация в представлении, произведет значения, которые удовлетворяют предикату этого представления.
Модификация других представлений базирующихся на первом текущем,
является все еще допустимой, если эти представления не защищены предложениями WITH CHECK OPTION внутри этих представлений. Даже
если такие предложения установлены, они проверяют только те предикаты
представлений в которых они содержатся. Так например, даже если представление Myratings создавалось следующим образом
CREATE VIEW Myratings
AS SELECT *
FROM Highratings
WITH CHECK OPTION;
проблема не будет решена. Предложение WITH CHECK OPTION будет
исследовать только предикат представления Myratings. Пока у Myratings,
фактически, не имеется никакого предиката, WITH CHECK OPTION ни-
чего не будет делать. Если используется предикат, то он будет проверять-
с всякий раз, когда представление Myratings будет модифицироваться,
но предикат Highratings все равно будет проигнорирован.
Это - дефект в стандарте ANSI, который у большинство программ исправлен. Вы можете попробовать использовать представление наподобие последнего примера и посмотреть избавлена ли ваша система от этого дефекта. ( Попытка выяснить это самостоятельно может быть иногда быть проще
и яснее, чем поиск ответа в документации системы. )
РАБОТА С SQL
1. Какое из этих представлений - модифицируемое ?
#1 CREATE VIEW Dailyorders
AS SELECT DISTINCT cnum, snum, onum,
odate
FROM Orders;
#2 CREATE VIEW Custotals
AS SELECT cname, SUM (amt)
FROM Orders, Customers
WHERE Orders.cnum = customer.cnum
GROUP BY cname;
#3 CREATE VIEW Thirdorders
AS SELECT *
FROM Dailyorders
WHERE odate = 10/03/1990;
#4 CREATE VIEW Nullcities
AS SELECT snum, sname, city
FROM Salespeople
WHERE city IS NULL
OR sname BETWEEN 'A' AND 'MZ';
2. Создайте представление таблицы Продавцов с именем Commissions
(Комиссионные). Это представление должно включать только пол
comm и snum. С помощью этого представления, можно будет вводить
или изменять комиссионные, но только для значений между .10 и .20.
3. Некоторые SQL реализации имеют встроенную константу представляющую текущую дату, иногда называемую " CURDATE ".
Слово CURDATE может следовательно использоваться в операторе SQL,
и заменяться текущей датой, когда его значение станет доступным с по-
мощью таких команд как SELECT или INSERT. Мы будем использовать
представление таблицы Порядков с именем Entryorders для вставки строк
в таблицу Порядков. Создайте таблицу порядков, так чтобы CURDATE
автоматически вставлялась в поле odate если не указано другого значения. Затем создайте представление Entryorders, так чтобы значения не
могли быть указаны.
( См.