Иван Задворьев - Язык PL/SQL
- Название:Язык PL/SQL
- Автор:
- Жанр:
- Издательство:Array SelfPub.ru
- Год:2018
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Иван Задворьев - Язык PL/SQL краткое содержание
Язык PL/SQL - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Конструкция USING со списком переменных и констант используется для передачи значений, которые должны быть связаны с имеющимися в тексте предложения SQL связываемыми переменными. Связывание значений в NDS осуществляется по позициям связываемых переменных. Количество передаваемых значений, естественно, должно совпадать c количеством связываемых переменных.
Для SQL-запросов команда EXECUTE IMMEDIATE фактически является аналогом команды SELECT INTO с таким же ограничением на результирующую выборку: запросом должна отбираться ровно одна строка, в противном случае инициируются предопределенные исключения.
Рассмотрим пример использования команды EXECUTE IMMEDIATE:
CREATE TABLE tab1 (at1 INT, at2 VARCHAR2(1));
INSERT INTO tab1 VALUES(1,'A');
INSERT INTO tab1 VALUES(2,'B');
SQL> DECLARE
2 l_tab1 tab1%ROWTYPE;
3 l_sql_text VARCHAR2(100) := 'SELECT * FROM tab1 WHERE at1>=:p_at1';
4 BEGIN
5
6 EXECUTE IMMEDIATE l_sql_text INTO l_tab1_rec USING 2;
7 DBMS_OUTPUT.PUT_LINE('Отобранная строка: '||l_tab1.at1||l_tab1.at2);
8
9 BEGIN
10 EXECUTE IMMEDIATE l_sql_text INTO l_tab1 USING 1;
11 EXCEPTION
12 WHEN OTHERS THEN
13 DBMS_OUTPUT.PUT_LINE(SQLERRM);
14 END;
15
16 BEGIN
17 EXECUTE IMMEDIATE l_sql_text INTO l_tab1 USING 3;
18 EXCEPTION
19 WHEN OTHERS THEN
20 DBMS_OUTPUT.PUT_LINE(SQLERRM);
21 END;
22
23 END;
24 /
Отобранная строка: 2B
ORA-01422: exact fetch returns more than requested number of rows
ORA-01403: no data found
PL/SQL procedure successfully completed.
Рассмотрим еще два примера использования NDS.
Пусть база данных спроектирована таким образом, что у каждой таблицы столбец первичного ключа называется id и имеет тип INTEGER.
Напишем процедуру, которая удаляет строку в любой таблице по значению ее первичного ключа. Параметрами процедуры будут имя таблицы и значение столбца id удаляемой строки.
CREATE TABLE tab1(id INTEGER PRIMARY KEY,at1 CHAR(1));
INSERT INTO tab1 VALUES(1,'a');
INSERT INTO tab1 VALUES(2,'b');
CREATE TABLE tab2(id INTEGER PRIMARY KEY,at1 CHAR(1));
INSERT INTO tab2 VALUES(20,'x');
INSERT INTO tab2 VALUES(30,'y');
SQL> CREATE OR REPLACE PROCEDURE delete_by_id (p_table_name IN VARCHAR2,
2 p_id IN INTEGER) IS
3 BEGIN
4 EXECUTE IMMEDIATE 'DELETE FROM '||p_table_name||' WHERE id=:p_id'
5 USING p_id;
6 DBMS_OUTPUT.PUT_LINE('In table '||p_table_name||' '
7 ||SQL%ROWCOUNT||' rows deleted');
8 END;
9 /
Procedure created.
SQL> set serveroutput on
SQL> EXECUTE delete_by_id('tab1',1);
In table tab1 1 rows deleted
PL/SQL procedure successfully completed.
SQL> EXECUTE delete_by_id('tab1',-1);
In table tab1 0 rows deleted
PL/SQL procedure successfully completed.
SQL> EXECUTE delete_by_id('tab2',20);
In table tab2 1 rows deleted
PL/SQL procedure successfully completed.
Для NDS в PL/SQL поддерживаются средства массовой обработки данных (bulk processing). Конструкция BULK COLLECT указывается в том случае, когда известно, что SQL-запрос может иметь в результирующей выборке не одну, а несколько строк. Тогда переменной, в которую помещается результирующая выборка, должна быть коллекция, то есть и здесь прослеживается аналогия с командой SELECT INTO для статических предложений SQL. Также команда EXECUTE IMMEDIATE может использоваться совместно с рассматриваемой ранее командой FORALL.
Вернем содержимое таблиц tab1, tab2 в исходное состояние и создадим теперь процедуру print_id_list со считыванием в коллекцию всех строк результирующей выборки с помощью конструкции BULK COLLECT.
SQL> CREATE OR REPLACE PROCEDURE print_id_list(p_table_name IN VARCHAR2,
2 p_id IN INTEGER) IS
3 TYPE t_table IS TABLE OF INTEGER;
4 l_table t_table;
5 BEGIN
6 EXECUTE IMMEDIATE 'SELECT id FROM '||p_table_name||' WHERE id>:p_id'
7 BULK COLLECT INTO l_table
8 USING p_id;
9 FOR i IN 1..l_table.COUNT LOOP
10 DBMS_OUTPUT.PUT_LINE(l_table(i));
11 END LOOP;
12 END;
13 /
Procedure created.
SQL> EXECUTE print_id_list('tab1',0);
1
2
PL/SQL procedure successfully completed.
SQL> EXECUTE print_id_list('tab2',20);
30
PL/SQL procedure successfully completed.
Как видно, использование NDS позволяет писать очень компактный код.
Пакет DBMS_SQL
Использование встроенного пакета DBMS_SQL для выполнения динамического SQL предусматривает в общем случае последовательность из 8 этапов.
Таблица 12.Этапы выполнения динамического SQL с помощью DBMS_SQL.
Программа
Описание этапа
OPEN_CURSOR
открывается курсор DBMS_SQL
PARSE
производится синтаксический разбор предложения SQL в курсоре (DDL-команды сразу и выполняются на этом этапе)
BIND_VARIABLE
со всеми связываемыми переменными предложения SQL в курсоре связываются значения
DEFINE_COLUMN
для SQL-запросов указывается, значения каких столбцов выборки в какие переменные PL/SQL будут считываться
EXECUTE
для открытого курсора выполняется предложение SQL
FETCH_ROWS
для SQL-запросов считывается строка выборки (обычно считывание осуществляется в цикле по всей выборке)
COLUMN_VALUE
переменным PL/SQL присваиваются значения столбцов текущей считанной строки из курсора
CLOSE_CURSOR
закрывается курсор DBMS_SQL
Перепишем процедуру print_id_list с использованием вместо NDS встроенного пакета DBMS_SQL.
SQL> CREATE PROCEDURE print_id_list_dbms_sql(p_table_name IN VARCHAR2,
2 p_id IN INTEGER) IS
3 c_cursor INTEGER;
4 ignore INTEGER;
5 l_id INTEGER;
6 BEGIN
7 c_cursor := DBMS_SQL.open_cursor;
8 DBMS_SQL.parse(c_cursor,
9 'SELECT ID FROM '||p_table_name||' WHERE id>:p_id',
10 DBMS_SQL.NATIVE);
11 DBMS_SQL.define_column(c_cursor, 1, l_id);
12 DBMS_SQL.bind_variable(c_cursor, 'p_id', p_id);
13 ignore := DBMS_SQL.execute(c_cursor);
14 LOOP
15 IF DBMS_SQL.fetch_rows(c_cursor)>0 THEN
16 DBMS_SQL.column_value(c_cursor, 1, l_id);
17 DBMS_OUTPUT.PUT_LINE(l_id);
18 ELSE
19 EXIT;
20 END IF;
21 END LOOP;
22 DBMS_SQL.close_cursor(c_cursor);
23 END;
24 /
Procedure created.
SQL> EXECUTE print_id_list_dbms_sql('tab1',0);
1
2
PL/SQL procedure successfully completed.
SQL> EXECUTE print_id_list_dbms_sql('tab2',20);
30
PL/SQL procedure successfully completed.
Код новой версии процедуры print_id_list выглядит более громоздким. Этим и объясняется то, что пакет DBMS_SQL, как правило, используют только тогда, когда использовать NDS нельзя. В остальных случаях обходятся одной строчкой кода с командой EXECUTE IMMEDIATE.
Выполнение динамического SQL четвертой категории
Читатель, вероятно, уже заметил в синтаксисе команды EXECUTE IMMEDIATE ограничение, мешающее использовать встроенный динамический SQL во всех случаях – в EXECUTE IMMEDIATE после конструкций INTO и USING необходимо указывать жестко заданные перечни переменных и констант PL/SQL. Они фиксируются на этапе написания программы и изменяться не могут. Поэтому NDS не подходит для выполнения четвертой категории динамического SQL, когда до стадии выполнения неизвестно количество столбцов результирующей выборки или количество параметров.
Пакет DBMS_SQL позволяет выполнять динамический SQL четвертой категории, так как на стадии выполнения его процедуры и функции можно вызывать любое количество раз. То есть надо просто вызывать процедуру DBMS_SQL.DEFINE_COLUMN и функцию DBMS_SQL.COLUMN_VALUE по числу возвращаемых SQL-запросом столбцов, а процедуру DBMS_SQL.BIND_VARIABLE – по числу имен связываемых переменных.
Задание для самостоятельной разработки
Пусть список значений параметров, которые указывают пользователи на web-странице при подборе моделей телефонов, формируется frontend-приложением в виде символьной строки из пар «параметр=значение», разделенных символом «;». Для цены передается значение вида from/to с указанными пользователем границами диапазона. Название параметра соответствует названию столбца таблицы.
Примеры поисковых запросов:
1) LTE=1;dual_sim=1
2) price=10000/12000;color=black;LTE=1
Необходимо написать процедуру PL/SQL, которая печатает на экране список моделей телефонов, удовлетворяющих заданным условиям. Понятно, что это будет процедура, динамически формирующая и выполняющая нерегламентированные запросы SQL.
Читать дальшеИнтервал:
Закладка: