Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
all_lab.doc
Скачиваний:
56
Добавлен:
14.11.2019
Размер:
1.42 Mб
Скачать

9. Курсоры в MySql. Представления. Конструкции управления потоком данных

Если результирующий запрос возвращает одну запись, поместить результаты в промежуточные переменные можно при помощи оператора SELECT … INTO … FROM. Однако результирующие таблицы чаще содержат несколько записей и использование такого запроса совместно с оператором SELECT … INTO … FROM приводит к возникновению ошибки «Результат содержит более чем одну строку».

Избежать возникновения ошибки можно, например, добавив предложение LIMIT 1 или назначив CONTINUE-обработчик ошибок. Однако функция будет реализовывать совсем не то поведение, которое ожидает пользователь. Кроме того, существуют ситуации, когда требуется обработать именно многострочную результирующую таблицу.

Например, пусть требуется получить записи таблицы catalogs и на основании этих записей создать новую таблицу letter_catalogs, в которой названия каталогов будут представлены в верхнем регистре.

Таблица catalogs представляет собой, например:

id_catalog

name

  1

Процессоры

  2

Материнские платы

  3

Видеоадаптеры

  4

Жёсткие диски

  5

Оперативная память

  6

Периферия

Решить эту задачу можно при помощи курсоров, которые позволяют в цикле просмотреть каждую строку результирующей таблицы запросов. Работа с курсорами происходит по следующему алгоритму:

  • При помощи инструкции DECLARE CURSOR связывается имя курсора с выполняемым запросом.

  • Оператор OPEN выполняет запрос, связанный с курсором, и устанавливает курсор перед первой записью результирующей таблицы.

  • Оператор FETCH помещает курсор на первую запись результирующей таблицы и извлекает данные из записи в локальные переменные хранимой процедуры. Повторный вызов оператора FETCH приводит к перемещению курсора к следующей записи и так до тех пор, пока записи в результирующей таблице не будут исчерпаны. Эту операцию удобно осуществлять в цикле.

  • Оператор CLOSE прекращает доступ к результирующей таблице и ликвидирует связь между курсором и результирующей таблицей.

ЗАМЕЧАНИЕ. Работа с курсорами похожа на работу с файлами – сначала происходит открытие курсора, затем чтение и после закрытие.

Оператор DECLARE CURSOR объявляет курсор и имеет следующий синтаксис:

DECLARE cursor_name CURSOR FOR select_statement

Оператор объявляет курсор с именем cursor_name для SELECT-запроса select_statement. В рамках хранимой процедуры имя cursor_name должно быть уникальным.

ЗАМЕЧАНИЕ. В SELECT-запросе select_statement не допускается использовать запрос вида SELECT … INTO … FROM.

В момент объявления курсора при помощи оператора DECLARE CURSOR SELECT-запрос select_statement не выполняется. Его выполнение откладывается до момента вызова оператора OPEN, который имеет следующий синтаксис:

OPEN cursor_name

Оператор OPEN принимает имя курсора cursor_name. Далее записи извлекаются при помощи оператора FETCH, который имеет следующий синтаксис:

FETCH cursor_name INTO var, var1,…

После ключевого слова INTO должно быть приведено столько локальных переменных, сколько полей возвращает SELECT-запрос select_statement.

Оператор CLOSE имеет синтаксис, схожий с оператором OPEN:

CLOSE cursor_name

Таким образом, основные команды, необходимые для работы с курсором:

Объявление курсоров

DECLARE имя_курсора CURSOR FOR onepaтop_sql

Во время процедуры можно определять многочисленные курсоры, но имя каждого из них должно быть уникальным.

Оператор открытия курсора OPEN

OPEN имя_курсора

Данный оператор открывает объявленный ранее курсор.

Оператор выборки курсора FETCH

FETCH имя курсора INTO имя переменной [, имя_переменной] . ..

Данный оператор выполняет выборку следующей строки (если строка существует) с помощью указанного открытого курсора и продвигает указатель курсора.

Оператор закрытия курсора CLOSE

CLOSE имя_курсора

Данный оператор закрывает открытый ранее курсор.

Вернемся к поставленной выше задаче – созданию новой таблицы letter_catalogs с именами каталогов в верхнем регистре. Создадим таблицу letter_catalogs при помощи следующего запроса:

CREATE TABLE IF NOT EXISTS letter_catalogs

(id_catalog INT,

name TINYTEXT);

Тогда процедура, выполняющая поставленную задачу, может выглядеть так:

CREATE PROCEDURE curcatalogs()

BEGIN

/* Объявляем локальные переменные */

DECLARE id INT;

DECLARE is_end INT DEFAULT 0;

DECLARE cat TINYTEXT;

/* Объявляем курсор */

DECLARE curcat CURSOR FOR SELECT * FROM catalogs;

/* Объявляем обработчик для ситуации, когда курсор достигает конца результирующей таблицы */

DECLARE CONTINUE HANDLER FOR NOT FOUND SET is_end = 1;

/* Открываем курсор */

OPEN curcat;

/* В цикле читаем данные у курсора и добавляем записи */

wet: LOOP

FETCH curcat INTO id, cat;

IF is_end THEN LEAVE wet;

END IF;

INSERT INTO letter_catalogs VALUES (id, UPPER(cat))

END LOOP wet;

/* Закрываем курсор */

CLOSE curcat;

END

Вызов процедуры осуществляется с помощью скрипта CALL curcatalogs().

Как видно из кода, хранимая процедура curcatalogs() заполняет таблицу letter_catalogs записями из таблицы catalogs, переводя названия каталогов в верхний регистр. Нетрудно переделать хранимую процедуру таким образом, чтобы она изменяла записи существующей таблицы catalogs. Для этого запрос

INSERT INTO letter_catalogs VALUES (id, UPPER(cat))

следует заменить UPDATE-запросом

UPDATE catalogs SET name = UPPER(cat) where id_catalog = id;

Представления

Основной структурной едницей в реляционных базах данных являются таблицы. Однако язык запросов SQL предоставляет еще один способ организации данных – представления. Представление – это запрос на выборку (SELECT), которому присваивается уникальное имя и который можно сохранять или удалять из базы данных как обычную хранимую процедуру. Представления позволяют увидеть результаты сохраненного запроса, таким образом, как будто это полноценная таблица базы данных.

Когда СУБД MySQL встречает в запросе ссылку на представление, она отыскивает его определение, сохраненное в базе данных. Затем происходит преобразование пользовательского запроса с участием представления в эквивалентный запрос к исходным таблицам. После чего происходит выполнение запроса. Таким образом, клиент может работать с представлениями так, как если бы они существовали как независимые таблицы. Если определение предcтавления простое, то каждая строка представления формируется «на лету». Если определение сложное, СУБД MySQL «материализует» представление в виде временной таблицы в оперативной памяти или на жестком диске.

Клиент, обращаясь к представлению, будет видеть только столбцы результирующей таблицы. При этом не имеет значение, сколько столбцов в исходной таблице и является ли SELECT-запрос, лежащий в основе представления, одно- или многотабличным. Кроме того, клиенту можно запретить обращаться к исходным таблицам, но снабдить привилегиями обращения к представлениям. Таким образом, на одном и том же наборе таблиц можно создать гибкие системы доступа к таблицам базы данных.

Создание представлений осуществляется при помощи операторв CREATE VIEW. Например, создадим представление cat, которое дублирует таблицу catalogs учебной базы test.

CREATE VIEW cat AS SELECT * FROM `catalogs`;

Просмотр представлени:

SELECT * FROM cat;

id_catalog

name

  1

Процессоры

  2

Материнские платы

  3

Видеоадаптеры

  4

Жёсткие диски

  5

Оперативная память

  6

Периферия

В каталоге данных для представления cat будет создан файл cat.frm, который, в отличие от файлов определения структуры таблиц, является не бинарным, а текстовым.

Структура файла cat.frm представления cat:

TYPE=VIEW

query=select `test`.`catalogs`.`id_catalog` AS `id_catalog`,`test`.`catalogs`.`name` AS `name` from `test`.`catalogs`

md5=31063ec7204a4b56c4f0b7350622011d

updatable=1

algorithm=0

definer_user=root

definer_host=localhost

suid=1

with_check_option=0

revision=1

timestamp=2007-03-15 11:56:43

create-version=1

source=SELECT * FROM `catalogs`

Представление рассматривается СУБД MySQL как полноценная таблица и может быть просмотрено в списке таблиц базы данных при помощи оператора SHOW TABLES.

При создании представления можно явно указать список столбцов и даже изменить их названия и порядок следования, например:

CREATE VIEW cat1 (catalog, id)

AS SELECT name, id_catalog FROM `catalogs`;

catalog

id

Процессоры

  1

Материнские платы

  2

Видеоадаптеры

  3

Жёсткие диски

  4

Оперативная память

  5

Периферия

  6

Как видно из примера, название столбца name меняется на catalog, а id_catalog на id. При этом порядок их следования меняется на обратный. При формировании списка столбцов представления задаются только имена столбцов, тип данных, длина и другие характеристики берутся из определения столбца исходной таблицы.

В качестве столбцов представления могут выступать вычисляемые столбцы. Пусть для таблицы products следует создать представление goods, содержащее имя товарной позиции, а также ее цену в рублях, долларах и евро. Пусть курс доллара будет составлять 28,8 рублей, а евро 34,5 рублей, тогда запрос на создание представления может выглядеть так:

CREATE OR REPLACE VIEW goods (name, rubl, doll, euro)

AS SELECT name, price, price/28.8, price/34.5 FROM `products`;

Для удаления представлений предназначен оператор DROP VIEW, для редактирвоания – ALTER VIEW или CREATE OR REPLACE VIEW. Оператор SHOW CRATE VIEW позволяет просмотреть струкутру оператора CREATE VIEW, при помощи которого было создано представление.

Конструкции управления потоком данных

В MySQL реализованы конструкции IF, CASE, LOOP, WHILE, ITERATE и LEAVE, которые позволяют управлять потоком данных. Каждая из этих конструкций может включать как единственный оператор, так и блок операторов при использовании составного оператора BEGIN...END. Конструкции можно представлять в форме вложений.

Циклы FOR на данный момент не поддерживаются.

Оператор IF

IF условие_поиска THEN оператор (ы)

[ELSEIF условие_поиска THEN оператор (ы)]

[ELSE оператор (ы)]

END IF

IF реализует базовую конструкцию ветвления. Если значение условие_поиска является истинным, будет выполнен соответствующий SQL-оператор. Если совпадения с условие_поиска не найдены, выполняться будет оператор, указанный в конструкции ELSE.

Оператор CASE

CASE значение_саsе

WHEN значение_whеп THEN оператор

[WHEN значение_when THEN оператор . . . ]

[ELSE оператор]

END CASE

Или:

CASE

WHEN условие_поиска THEN оператор

[WHEN условие__поиска THEN оператор . . . ]

[ELSE оператор]

END CASE

CASE реализует сложную конструкцию ветвления. Если значение условие__поиска является истинным, будет выполнен соответствующий SQL-оператор. Если совпадения с условие_поиска не найдены, выполняться будет оператор из конструкции ELSE.

На заметку!

Синтаксис оператора CASE внутри хранимой процедуры немного отличается от синтаксиса SQL-выражения CASE. Оператор CASE не может содержать конструкцию ELSE NULL, и его выполнение завершается с помощью END CASE, а не END.

Оператор LOOP

[метка__начала:] LOOP

оператор (ы)

END LOOP [метка_конца]

LOOP реализует простую конструкцию цикла, допуская повторное выполнение какого-то конкретного оператора или группы операторов. Операторы в цикле повторяются до выхода из этого цикла, для чего обычно используется оператор LEAVE.

Значения метка__начала и метка_конца, если заданы оба, должны быть одинаковыми.

Оператор LEAVE

LEAVE метка

Данный оператор используется для выхода из конструкции управления потоком выполнения. Оператор LEAVE эквивалентен оператору break в С-подобных языках программирования.

Оператор ITERATE

ITERATE метка

ITERATE может появиться только при использовании операторов LOOP, REPEAT и WHILE. ITERATE означает "повторить цикл снова". Оператор ITERATE эквивалентен оператору continue в С-подобных языках программирования.

Например:

CREATE PROCEDURE doiterate(p1 INT)

BEGIN

labell: LOOP

SET p1 = p1 + 1;

IF p1 < 10 THEN ITERATE labell; END IF;

LEAVE labell;

END LOOP labell;

SET @z = p1;

END

Вызываем процедуру:

CALL doiterate(6);

Смотрим результат работы процедуры:

SELECT @z;

Оператор REPEAT

[метка_начала:] REPEAT

оператор (ы)

UNTIL условие_поиска

END REPEAT [метка_конца]

Команды, указанные внутри оператора REPEAT, повторяются до тех пор, пока будет истинным условие условие_поиска.

Значения метка_начала и метка__конца, если заданы оба, должны быть одинаковыми.

Например:

CREATE PROCEDURE dorepeat(p1 INT)

BEGIN

SET @x = 0;

REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;

END

Вызываем процедуру:

CALL dorepeat(1000);

Смотрим результат работы процедуры:

SELECT @x;

Получаем, что @x = 1001

Оператор WHILE

[метка начала:] WHILE условие_поиска DO

оператор (ы)

END WHILE [метка__конца]

Команды, указанные внутри оператора WHILE повторяются до тех пор, пока будет истинным условие условие_поиска.

Значения метка_начала и метка_конца, если заданы оба, должны быть одинаковыми.

Например:

CREATE PROCEDURE dowhile()

BEGIN

DECLARE vl INT DEFAULT 5;

WHILE vl > 0 DO

SET vl = vl - 1;

END WHILE;

END

Задания

Вариант 1

  1. С использованием курсора разработать процедуру, которая в отдельную таблицу помещает список книг, вышедших в издательстве «Мир».

  2. С использованием курсора разработать процедуру, которая в таблице АВТОР делает следующее обновление – в поле «Отчество» оставляет только первые 3 символа.

Вариант 2

  1. С использованием курсора разработать процедуру, которая в отдельную таблицу выводит список рейсов до Москвы.

  2. С использованием курсора разработать процедуру, которая в таблице БИЛЕТ делает следующее обновление – фамилию пассажира записывает в обратном порядке.

Вариант 3

  1. С использованием курсора разработать процедуру, которая в отдельную таблицу выводит список десертов.

  2. С использованием курсора разработать процедуру, которая в таблице КОМПОНЕНТ делает следующее обновление – в названии компонентов все буквы «а» меняет на «*».

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]