Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Базы данных. Практический курс. В 2 частях. Ч.1. Объектно-реляционные базы данных на примере PostgreSQL 9.5. Учебное пособие.pdf
Скачиваний:
0
Добавлен:
06.09.2026
Размер:
2 Мб
Скачать
Глава 4. Применение SQL 4.1. SQL-представления
ArtistName AreaCode PhoneNumber
Selma Warning 253 555-1234 Susan Wu 721 555-1234 Donald G. Gray 705 555-1345 Lynda Johnson 703 555-1000 Chris Wilkens 206 555-1234
Можно скрывать от просмотра и строки таблиц. Для этого в
определении представления должно присутствовать предложение
WHERE. Следующий оператор определяет представление, содержа-
щее имена и номера телефонов всех клиентов, проживающих в штате Вашингтон:
CREATE VIEW BasicCustomerDataWa AS SELECT Name, PhoneNumber FROM CUSTOMER WHERE State = ’WA’;
Результирующая таблица будет такая:
Name PhoneNumber
Jeffrey Janes 555-1345 Tiffany Twilight 555-1000 Fred Smathers 555-1234 Chris Wilkens 555-1234
Как и требовалось, в таблице присутствуют сведения только о тех клиентах, которые проживают в штате Вашингтон. Данный факт не является очевидным, поскольку столбец State не входит в результат. Это может быть хорошо или плохо в зависимости от того, как используется представление. Если оно используется только в тех случаях, когда значение имеют лишь клиенты из Вашингтона, это хорошо; в противном случае это будет дезориентировать поль­зователя, создавая впечатление, что кроме перечисленных персон, у галереи больше нет клиентов.

4.1.2 Использование представлений для отображения вычисляемых столбцов

Еще одно применение представлений – отображение резуль-
татов вычислений, не прибегая к вводу формул пользователем. На-
71
4.1. SQL-представления Глава 4. Применение SQL
пример, следующее представление объединяет столбцы AreaCode и
PhoneNumber и форматирует результат:
CREATE VIEW CustomerPhone AS SELECT Name,
(’(’ || AreaCode || ’)’) || PhoneNumber AS Phone
FROM CUSTOMER;
Допустим, пользователь вводит следующий запрос:
SELECT * FROM CustomerPhone;
Результаты выполнения этого запроса будут следующими:
Name Phone
Jeffrey Janes (206)555-1345 David Smith (303)555-5434 Tiffany Twilight (206)555-1000 Fred Smathers (206)555-1234 Mary Beth Frederickson (303)555-1000 Selma Warning (253)555-1234 Susan Wu (721)555-1234 Donald G. Gray (705)555-1345 Lynda Johnson (703)555-1000 Chris Wilkens (206)555-1234
Выполнение необходимых вычислений в представлениях име­ет два преимущества. Во-первых, это избавляет пользователей от необходимости вводить математическое выражение, чтобы полу­чить желаемый результат (а также от необходимости знать, как это делается). Во-вторых, это обеспечивает единообразие результатов. Если каждый разработчик, использующий вычисления, будет пи­сать собственные выражения, то они, скорее всего, будут написаны по-разному, из-за чего результаты будут иметь неодинаковый вид.

4.1.3 Использование представлений для скрытия сложного синтаксиса

Еще одно применение представлений – скрытие SQL-запросов со сложным синтаксисом. Это может делаться для того, чтобы из­бавить разработчиков от необходимости вводить сложный запрос всякий раз, когда им требуется определенное представление, или
72
Глава 4. Применение SQL 4.1. SQL-представления
для того, чтобы разработчики, не знающие SQL, могли тем не менее воспользоваться преимуществами, которые предоставляют сложные SQL-запросы. Кроме того, как и в случае использования представлений для вычислений, это обеспечивает единообразие результатов.
Два наиболее распространенных варианта использования представлений в данной ипостаси – это скрытие соединений и скры­тие вложенных запросов.
Предположим, что продавцам-консультантам галереи необхо­димо знать, какими художниками интересуется тот или иной кли­ент. Поскольку связь между сущностями CUSTOMER и ARTIST име­ет вид N:M, она представлена в виде таблицы пересечения. Та­ким образом, чтобы отобразить сведения об интересах клиентов, необходимо выполнить два соединения: сначала соединить табли­цы CUSTOMER и CUSTOMER_ARTIST_INT, а затем полученный результат соединить с таблицей ARTIST. Представление, содержащее эти два соединения, конструируется с помощью следующего SQL-запроса:
CREATE VIEW CustomerInterests AS SELECT C.Name AS Customer, A.Name AS Artist FROM CUSTOMER C JOIN CUSTOMER_ARTIST_INT CI
ON C.CustomerID = CI.CustomerID
JOIN ARTIST A
ON CI.ArtistID = A.ArtistID;
Данный запрос выполняет стандартное двойное соединение. Обратите внимание на использование псевдонимов для таблиц (С вместо CUSTOMER, CI вместо CUSTOMER_ARTIST_INT, A вместо ARTIST). Такие псевдонимы упрощают соединения. Например, проще на­писать C.CustomerID = CI.CustomerID, чем CUSTOMER.CustomerID =
= CUSTOMER_ARTIST_INT.CustomerID. Использовать псевдонимы не
обязательно.
Также обратите внимание на переименование C.Name в
Customer и A.Name в Artist. Такое переименование выполнять необ-
ходимо, в противном случае в представлении оказались бы два
столбца с именем Name. СУБД не смогла бы различить эти два столб­ца и выдала бы ошибку при создании представления.
73
4.1. SQL-представления Глава 4. Применение SQL
Следующий оператор запрашивает данные из представления
CustomerInterests и сортирует результаты по столбцу Customer:
SELECT * FROM CustomerInterests ORDER BY Customer;
Результат получился следующий:
Customer Artist
Chris Wilkens Frings Chris Wilkens Tobey David Smith Tobey Donald G. Gray Tobey Fred Smathers Tobey Lynda Johnson Tobey Lynda Johnson Moos Lynda Johnson Frings Mary Beth Frederickson Frings Mary Beth Frederickson Moos Mary Beth Frederickson Tobey Selma Warning Tobey Selma Warning Miro Tiffany Twilight Chagall Tiffany Twilight Frings Tiffany Twilight Tobey
Представления используются также для скрытия группиров­ки и встроенных функций. Рассмотрим следующее определение представления:
CREATE VIEW ArtistWorkNet AS SELECT W.WorkID, Name, Title, Copy, AcquisitionPrice,
SalesPrice, (SalesPrice - AcquisitionPrice) AS NetPrice FROM TRANSACTION T JOIN WORK W
ON T.WorkID = W.WorkID JOIN ARTIST A
ON W.ArtistID = A.ArtistID;
Данное представление соединяет таблицы TRANSACTION, WORK и
ARTIST и создает вычисляемый столбец NetPrice. С этим представ-
лением можно выполнять различные операции на языке SQL, как если бы NetPrice был обычным столбцом таблицы. Например, что-
74
Глава 4. Применение SQL 4.1. SQL-представления
бы отобразить совокупную прибыль от продажи каждой картины, можно использовать следующий оператор:
SELECT Name, Title, Copy, SUM(NetPrice) AS TotalNet FROM ArtistWorkNet GROUP BY Name, Title, Copy;
Результаты выполнения этого запроса показаны ниже:
Name Title Copy TotalNet
Tobey Mystic Fabric 105/135 5250.00 Miro Mi Vida 7/10 44300.00 Tobey Slow Embers NC 7750.00 Tobey Mystic Fabric 99/135 27550.00 Chagall Northwest by Night 37/50 24500.00
У представлений имеется еще одно важное применения – они могут обеспечивать определенный уровень абстракции между при­ложением базы данных и реальными таблицами. Этот уровень аб­стракции может быть важен, когда источник данных может ме­няться. Чтобы понять, о чем идет речь, рассмотрим следующее определение представления:
CREATE VIEW CustomerTable1 AS SELECT * FROM CUSTOMER;
В сущности, это представление присваивает таблице CUSTOMER псевдоним CustomerTable1. Представление CustomerTable1 можно обрабатывать точно таким же образом, как и таблицу CUSTOMER.
Если в коде приложения используется имя CustomerTable1, то источник данных, на котором основано это представление, мо­жет меняться, не вызывая необходимости переписывать приложе­ние. Следовательно, в определенный момент в будущем, если ис­точником данных о клиентах станет другая таблица, например,
NEW_CUSTOMER, все, что потребуется сделать, – это переопределить
представление CustomerTable1 следующим образом:
CREATE VIEW CustomerTable1 AS SELECT * FROM NEW_CUSTOMER;
75
4.2. SQL-запросы в прикладных программах Глава 4. Применение SQL
Весь код приложения, в котором используется имя
CustomerTable1, без проблем будет работать с новым источником
данных.
Из-за потенциальной необходимости в изменении источников данных некоторые организации никогда не предоставляют разра­ботчикам доступ к реальным таблицам. Вместо этого используются представления, базирующиеся на данных из этих таблиц. Такая стратегия повышает гибкость для будущих проектов по разработке баз данных и упрощает их перепроектирование.

4.2 SQL-запросы в прикладных программах

SQL-запросы можно встраивать в триггеры, хранимые про­цедуры и прикладные программы. Для того чтобы встроить SQL-запросы в программный код, необходимо преодолеть два за­труднения. Во-первых, нужен какой-то способ, позволяющий запи­сывать результаты выполнения SQL-запросов в программные пере­менные. Это можно сделать по-разному. В одних случаях для это­го используются объектно-ориентированные программы, в других применяются более простые методы. Например, в PL/pgSQL (описа­ние данного языка представлено далее) следующий оператор при­сваивает переменной rowcount значение, равное количеству строк в таблице CUSTOMER:
SELECT COUNT(*) INTO rowcount FROM CUSTOMER;
Вторая трудность заключается в несоответствии парадигм SQL парадигмам языков программирования. Язык SQL оперирует множествами: большинство запросов SQL возвращают таблицу или набор строк. В отличие от этого, программы оперируют отдельными элементами или строками. Из-за этого отличия оператор, подобный приведенному ниже, не имеет смысла:
SELECT Name INTO custName FROM CUSTOMER;
Если в таблице CUSTOMER имеется 100 строк, то запрос столбца
Name возвратит 100 значений, в то время как переменная custName
может принять только одно значение.
76
Глава 4. Применение SQL 4.3. Хранимые процедуры
Чтобы преодолеть это затруднение, результаты выполнения SQL-запросов обрабатываются как коллекции. SQL-запрос возвра­щает набор строк. На первую строку помещается курсор, и данная строка обрабатывается. Затем курсор перемещается на следующую строку, и так далее, пока не будут обработаны все строки. Типичный процесс обработки выглядит так:
Использовать
коллекцию SQL (SELECT * FROM CUSTOMER);Поместить курсор на первую строку;
Пока курсор не вышел за пределы таблицы {
Присвоить custName значение столбца
Name в строке под курсором;
... Прочие операторы, использующие значение custName ...
Переместить курсор не следующую строку;
};
... Продолжение обработки...
Таким образом, строки, возвращенные SQL-запросом, обраба­тываются по одной. Именно таким является принцип встраивания SQL-запросов в программный код. Примеры будут представлены далее.

4.3 Хранимые процедуры

Хранимая процедура (stored procedure) – это программа, ко­торая выполняет некоторые действия с информацией в базе дан­ных и при этом сама хранится в базе данных. В PostgreSQL хра­нимые процедуры можно писать на собственном языке програм­мирования этой СУБД, носящим название PL/pgSQL (Procedural Language/PostGres Structured Query Language – процедурное рас­ширение языка SQL) или на таких языках, как PL/Perl, PL/Python и PL/Tcl, дополнительно можно использовать PL/Java, PL/PHP, PL/Py, PL/R, PL/Ruby, PL/Scheme, PL/sh и PL/V8, а также имеется поддерж­ка загрузки C-совместимых модулей.
Хранимые процедуры могут иметь входные параметры и воз­вращать результаты. В отличие от триггерных функций (см. под­раздел 4.4), которые принадлежат определенной таблице или пред-
77
4.3. Хранимые процедуры Глава 4. Применение SQL
ставлению, хранимые процедуры принадлежат базе данных в це­лом. Они могут вызываться любым процессом, использующим базу данных, при условии, что у этого процесса есть достаточные права доступа.
Хранимые процедуры используются для многих целей. Хотя администраторы баз данных используют их для выполнения рутин­ных задач администрирования, главной областью их применения являются все же приложения баз данных. Эти процедуры могут вызываться из прикладных программ, написанных на таких языках, как Java, C#, C++, Python и т. д., а также из веб-сценариев, напи­санных на JavaScript и подобных языках. Кроме того, эти процедуры можно вызывать в интерактивном режиме из командной оболочки psql.
Выделяют следующие преимущества хранимых процедур:
Большая безопасность.
Меньший сетевой трафик.
SQL-код можно оптимизировать.
Совместное использование кода между разработчиками.
В отличие от кода приложений, хранимые процедуры никогда не передаются на клиентские компьютеры. Она всегда находятся в базе данных и выполняются СУБД на том компьютере, где распола­гается сервер базы данных. Таким образом, они более безопасны, чем распространяемый код приложения, а кроме того, снижают сетевой трафик. Хранимые процедуры постепенно становятся пред­почтительным режимом реализации логики приложения в сети Ин­тернет и корпоративных интрасетях. Еще одно преимущество хра­нимых процедур заключается в том, что SQL-запросы в них могут быть оптимизированы компилятором СУБД.
Пример хранимой процедуры
Предположим, для нашего примера требуется возможность добавлять в базу данных сведения о новых клиентах и о том, какими художниками они интересуются. В частности, нужно записывать имя и телефон клиента, а также связывать его со всеми художни­ками выбранной национальности.
78
Глава 4. Применение SQL 4.3. Хранимые процедуры
В листинге 4.1 представлена хранимая процедура, выполня­ющая эту задачу. Процедура, которая называется customer_insert, принимает четыре параметра: newname (имя нового клиента),
newareacode (код региона), newphone (телефон) и artistnationality
(национальность художника). Ключевое слово IN указывает на то, что все эти параметры являются входными. Выходные параметры (которых у этой процедуры нет) обозначаются ключевым словом
OUT, а параметры, играющие роль и входных и выходных, – соче-
танием INOUT. Следует обратить внимание, что для параметра ука­зывается только тип данных, а длина не указывается. PostgreSQL определит длину из контекста.
Листинг 4.1.
CREATE OR REPLACE FUNCTION customer_insert(
newname IN char, newareacode IN char, newphone IN char, artistnationality IN char) RETURNS int AS $customer_insert$
DECLARE
artistcursor CURSOR FOR
SELECT ArtistID FROM ARTIST WHERE Nationality = artistnationality;
rowcount int;
BEGIN
SELECT Count(*) INTO rowcount FROM CUSTOMER WHERE Name = newname AND AreaCode = newareacode AND PhoneNumber = newphone;
IF rowcount > 0 THEN
RAISE EXCEPTION ’There is client in DB! Count is %!’,
rowcount;
END IF;
INSERT INTO CUSTOMER
(CustomerID, Name, AreaCode, PhoneNumber) VALUES (nextval(’seq_customer’), newname, newareacode, newphone);
79
4.3. Хранимые процедуры Глава 4. Применение SQL
FOR artist IN artistcursor LOOP
INSERT INTO CUSTOMER_ARTIST_INT
(CustomerID, ArtistID) VALUES (currval(’seq_customer’), artist.ArtistID);
RAISE INFO ’Artist %; Customer %’,
currval(’seq_customer’), artist.ArtistID;
END LOOP;
RAISE INFO ’Client is added!’;
RETURN 1; END; $customer_insert$ LANGUAGE plpgsql;
Раздел объявления переменных следует за ключевым словом
DECLARE. Оператор SELECT определяет переменную-курсор (cursor
variable) с именем artistcursor. Этот курсор выделяет из таблицы
ARTIST для обработки строки всех художников заданной националь-
ности.
В первой части процедуры проверяется, есть ли в базе ин­формация о данном клиенте. В этом случае никакие действия не предпринимаются, а пользователю с помощью оператора RAISE вы­водится соответствующее сообщение. Следует обратить внимание, что для вывода строки и значения переменной используется следу­ющий синтаксис:
RAISE уровень<> строка’<> %’ переменная<>;
В данном случае в качестве уровня могут быть указаны следую­щие значения: DEBUG, LOG, INFO, NOTICE, WARNING и EXCEPTION. Уровень
EXCEPTION используется по-умолчанию. При использовании уровня EXCEPTION вызывается исключение, завершающее текущую тран-
закцию с выводом сообщения об ошибке, остальные уровни лишь выводят сообщения с различным уровнем приоритета. Символ ’%’ используется для вставки в строку значения переменной.
Пользователь получит это сообщение только в том случае, ес­ли процедура будет вызвана из psql или pgAdmin III. В случае вызова процедуры иным путем, например с помощью браузера через Ин­тернет, пользователь не увидит этого сообщения. Чтобы сообщить
80
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]