
- •Краткий справочник по oracle
- •7. Функции sql и oracle7
- •7.1 Числовые функции
- •7.3. Функции работы с датами и временем
- •7.5. Групповые функции
- •9. Псевдо- столбцы и таблицы
- •10. Предложения (команды) sql Oracle7
- •Identified {by password | externally}
- •11. Фразы предложений (команд) sql Oracle7
- •12.2.3. Записи pl/sql
- •12.3.1. Явный курсор
- •12.3.1.2. Открытие курсора (open)
- •12.3.1.6. Атрибуты явного курсора
- •12.5. Обработка ошибок
- •Value_error ora-06502 Арифметическая ошибка, ошибка преобразования,
- •12.5.2. Исключительные ситуации, определяемые пользователем
- •13. Представления словарей данных
- •Index(create,create any, Создает, изменяет и удаляет индексы
- •Insert any,update any)
5. ВВЕДЕНИЕ В PL/SQL |
PL/SQL – "Programming Language for SQL", или "Procedured SQL" – процедурный SQL. Это расширение стандартного языка SQL, предназначенное для создания более сложных бизнес-правил (ограничения, процедуры, функции и триггеры) на стороне сервера ORACLE. Клиент-серверная архитектура подразумевает распределение бизнес-правил между клиентом и сервером. В зависимости от того, в какой процент всех бизнес-правил реализуется на клиенте по отношению к серверу, клиент будет либо "толстым", либо "тонким". Почему бизнес-правила перемещаются в отдельные модули и располагаются на сервере? Потому что в настоящий момент эти самые правила (правила вычисления налогов, начисления прибыли и т.д.) меняются очень часто и гораздо проще поменять их в отдельном месте, чем внутри программы с последующей рассылкой обновленных версий, тем более что этими бизнес-правилами могут пользоваться многие программы от разных разработчиков. Стандартный SQL позволяет создавать лишь простейшие бизнес-правила – ограничения (первичные ключи, вторичные ключи, статус NOT NULL, уникальные ключи – UNIQUE, контрольные ограничения – CHECK). PL/SQL позволяет создавать процедуры, функции и триггеры. Их общая цель – реализация сложной бизнес-логики модульным способом (т.е. компонент за компонентом, причем одни компоненты многократно используются другими). Кроме того, размещение бизнесс-правил на сервере значительно повышает производительность системы за счет того, что в большинстве случаев СУБД не интерпретирует SQL-запросы, а выполняет заранее скомпилированные хранимые процедуры. |
7. БЛОК PL/SQL |
Блок PL/SQL состоит из четырех секций:
Из всех секций обязательной является только одна - выполняемая секция. Простейший блок PL/SQL выглядит следующим образом: DECLARE s varchar(50); BEGIN s:='Hello!'; dbms_output.put_line(s); END; / Блоки могут быть вложены друг в друга. Последний, самый "верхний", блок PL/SQL называется базовым и всегда должен заканчивается символом "/", говорящий серверу о том, что можно приступать к компиляции введенной команды. Для того, чтобы приведенный выше пример вывел на экран сообщение, в среде SQL Plus необходимо ввести команду set serveroutput on Это настройка сессии в среде SQL Plus. Ее достаточно указать один раз сразу после соединения с сервером и она будет действовать пока существует установленное соединение. Данный блок не имеет заголовка, поэтому он называется анонимным. Только анонимные блоки могут быть вложены друг в друга, они могут использоваться в функциях, процедурах и триггерах. Если базовый блок не имеет заголовка, то есть является анонимным, то он не сохраняется на сервере, а выполняется сразу. Если же базовый блок имеет заголовок, то он хранится на сервере в виде скомпилированной процедуры, функции, пакета или триггера в зависимости от типа заголовка. В вышеприведенном примере использован оператор присваивания ":=" для инициализации переменной s. Вообще инициализация может проивзодиться прямо при объявлении переменной в секции объявления: ... DECLARE s varchar2(50):=`Hello`; BEGIN ... Секция заголовка: если она указана, то содержит спецификацию процедуры, функции, пакета или триггера, которая включает в себя название блока, а также описание входных и выходных параметров. Секция объявлений: предназначена для объявления переменных, констант, курсоров, которые будут использоваться в выполняемой секции процедуры, функции или триггера. Секция объявлений расположена сразу после секции заголовка, если она есть, и перед выполняемой секцией. В анонимных блоках и в триггерах для создания секции заголовка указывается ключевое слово DECLARE. Во всех остальных случаях ключевое слово DECLARE не используется. Выполняемая секция: содержит один или более операторов PL/SQL. Эту секцию еще называют телом процедуры, функции или триггера. Выполняемая секция начинается со слова BEGIN и заканчивается словом EXCEPTION, если есть секция исключений, или словом END. Секция исключений: содержит обработчики исключительных ситуаций. Исключительной ситуацией называют такую ситуацию, когда дальнейшее выполнение выполняемой секции не имеет смысла. |
8. ПОСЛЕДОВАТЕЛЬНОСТИ |
Назначение последовательностей состоит в генерации порядковых номеров. Это полезно для автоматической генерации значений для первичных ключей, а также для координирования ключей между различными строками или таблицами. Без генератора последовательностей порядковые номера можно было бы создавать лишь программным способом. Новое значение первичного ключа можно было бы получать выбором последнего программно вычисленного значения и наращиванием его.
|
8.1. СОЗДАНИЕ ПОСЛЕДОВАТЕЛЬНОСТЕЙ |
Создавайте последовательность с помощью команды SQL CREATE SEQUENCE. Например, следующая команда создает последовательность, используемую для генерации номеров дилеров для столбца DEALER_ID таблицы DEALERS (см. схему): CREATE SEQUENCE dealers_seq INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE CACHE 10; Заметьте, что для управления работой последовательности должны быть специфицированы некоторые параметры. С помощью этих параметров вы можете указать, должна ли последовательность возрастать или убывать, задать начальную точку последовательности, ее минимальное и максимальное значения, а также интервал приращения. Опция NOCYCLE указывает, что последовательность не сможет генерировать больше значений, когда достигнет своего максимального или минимального значения. Опция CACHE команды CREATE SEQUENCE обеспечивает предварительную генерацию нескольких номеров последовательности и поддерживает их в памяти (кэширует), так что доступ к ним ускоряется. Когда использован последний из номеров в кэше, ORACLE считывает в кэш очередную группу номеров. Для того чтобы указать максимальное или минимальное значение необходимо указать параметры MAXVALUE или MINVALUE соответственно. Например: CREATE SEQUENCE some_seq START WITH 1000 INCREMENT BY -1 MINVALUE 1 MAXVALUE 1000 CYCLE; После того как последовательность достигнет минимума (поскольку в данном случае она уменьшается) она вновь сгенерирует максимальное значение, то есть начнется новый цикл, поскольку указана опция CYCLE. Если параметр CYCLE не указан, то по достижении своего максимального или минимального значения и попытке сгенерировать новое значение последовательности, появится ошибка. Минимальный набор параметров при создании последовательности - это отсутствие всяких параметров, которые при этом принимают свои значения по умолчанию. То есть при выполнении следующего оператора CREATE SEQUENCE some_seq; будет создана последовательность, имеющая следующие характеристики: START WITH 1 INCREMENT BY 1 NOMAXVALUE NOMINVALUE NOCYCLE ... При определении имени последовательности обычно исходят из того, для какой цели она создается. Если это генерация значения для первичного ключа какой-то таблицы, то имя последовательности составляется из имени таблицы и прибавления к нему через подчеркивание слова "seq" или "sequence". Обычно для каждой из таблиц, для которой требуется автоматическая генерация значений первичного ключа, создается отдельная последовательность. |
8.2. ИЗМЕНЕНИЕ ПОСЛЕДОВАТЕЛЬНОСТЕЙ |
Вы можете изменить любой из параметров, определяющих поведение последовательности, за исключением начального номера. Чтобы изменить начальную точку последовательности, удалите эту последовательность и заново создайте ее. Чтобы изменить последовательность, используйте команду ALTER SEQUENCE. Например, следующее предложение изменяет последовательность dealers_seq: ALTER SEQUENCE dealers_seq INCREMENT BY 10 MAXVALUE 10000 CYCLE CACHE 20; |
8.3. ИСПОЛЬЗОВАНИЕ ПОСЛЕДОВАТЕЛЬНОСТЕЙ |
Обращение к последовательности: Обращение к последовательности осуществляется в предложениях SQL через псевдостолбцы NEXTVAL и CURRVAL; каждый новый номер данной последовательности генерируется обращением к ее псевдостолбцу NEXTVAL, тогда как текущий номер последовательности можно извлекать неоднократно путем обращения к ее псевдостолбцу CURRVAL. NEXTVAL и CURRVAL не являются зарезервированными или ключевыми словами; их можно использовать как имена псевдостолбцов в предложениях SQL, таких как SELECT, INSERT или UPDATE. Используя псевдостолбец CURRVAL всегда можно узнать текущее значение последовательности: SELECT dealers_seq.CURRVAL from dual; Генерация номеров последовательности через NEXTVAL. Чтобы сгенерировать и возвратить очередной номер данной последовательности, обратитесь к seq_name.NEXTVAL, где seq_name - имя последовательности. Например, предположим, что создается новый дилер. Номер последовательности можно специфицировать в списке вставляемых значений как номер нового дилера, например: INSERT INTO dealers (dealer_id, name, procent) VALUES (dealers_seq.NEXTVAL, `Василий Иванович`, 10); Первое обращение к dealers_seq.NEXTVAL возвратит значение 1 (поскольку START WITH 1). Каждое последующее предложение, обращающееся к dealers_seq.NEXTVAL, возвратит очередной номер данной последовательтности (2, 3, 4 и т.д.). Псевдостолбец NEXTVAL может генерировать столько новых номеров последовательности, сколько потребуется. Однако на одно предложение генерируется лишь один новый номер; иными словами, если в данном предложении SQL псевдостолбец NEXTVAL встречается несколько раз, то лишь для первого обращения будет возвращен новый номер последовательности, а все остальные обращения в этом предложении возвратят тот же самый номер. Например, в результате предложения INSERT INTO dealers values(dealers_seq.NEXTVAL, `Василий Иванович`,dealers_seq.NEXTVAL); в первое и третья поля вставятся одинаковые значения. После того как очередной номер последовательности сгенерирован, этот номер доступен лишь сессии, сгенерировавшей его. Независимо от подтверждения или отката транзакций, все пользователи, обращающиеся к dealers_seq.NEXTVAL, получают уникальные значения. Поэтому, если несколько пользователей одновременно обращаются к одной и той же последовательности, каждый из них может получать номера этой последовательности с промежутками, потому что номера генерируются также другими пользователями. Использование номеров последовательности через CURRVAL. Чтобы обратиться к текущему значению номера последовательности, которое уже было сгенерировано для вашей сессии, используйте обозначение seq_name.CURRVAL, где seq_name - имя последовательности. Псевдостолбец CURRVAL может использоваться лишь в том случае, если в текущей сессии уже было выдано обращение к seq_name.NEXTVAL для данной последовательности (не обязательно в текущей транзакции). CURRVAL можно использовать сколько угодно раз, в том числе несколько раз в одном и том же предложении. Очередной номер последовательности не будет сгенерирован, пока не будет выполнено очередное обращение к NEXTVAL. Продолжая предыдущий пример, вы могли бы создать нового менеджера, вставив в поле dealer_id текущее значение последовательности dealers_seq: INSERT INTO MANAGERS (manager_id, dealer_id, name) VALUES (managers_seq.NEXTVAL, dealers_seq.CURRVAL, `Петька`); Применения и ограничения NEXTVAL и CURRVAL NEXTVAL и CURRVAL могут использоваться в следующих местах:
NEXTVAL и CURRVAL не могут использоваться в следующих местах:
|
9. ПРОЦЕДУРЫ |
Процедуры (или хранимые процедуры) – это определенный набор инструкций, написанных на языке PL/SQL, и операторов DML. Вызов процедуры приводит к выполнению содержащихся в ней инструкций. Процедура хранится в базе данных, поэтому она и называется хранимой. Процедура – это именованный блок PL/SQL, то есть секция заголовка непустая. Секция заголовка называется еще спецификацией процедуры (procedure specification). Спецификация процедуры включает в себя имя процедуры и описание ее входных и выходных данных. После спецификации идет секция объявления, если это необходимо, выполняемая секция (или тело процедуры) и секция исключений (опять же необязательная). Создание процедуры: Создается процедура при помощи оператора CREATE PROCEDURE. Как правило эту команду пишут CREATE OR REPLACE PROCEDURE, что означает "создать или заменить процедуру, если уже есть процедура с таким именем и набором входных параметров". Конечно, перед заменой процедуры можно предварительно удалить ее прежний вариант, но на практике, как правило, используют именно такую конструкцию. Например, оператор создания процедуры, увеличивающей все цены на определенный процент может выглядить так: CREATE OR REPLACE PROCEDURE increase_prices(procent IN NUMBER:=10) AS BEGIN Update prices set value=value*procent; END; / Входные и выходные параметры: Между именем входного параметра и его типом можно указывать два специальных слова – IN и/или OUT. Указание IN будет означать, что в данной переменной процедуре было передано входное значение. Указание OUT означает, то эту переменную можно использовать для возврата какого-то значения. Можно также указывать одновременно IN и OUT. Если ничего не указано, то подразумевается IN. Важно: Типы данных в процедуре не могут иметь спецификаций размера. Например, нужно указывать NUMBER, но не NUMBER(10,2). Значения по умолчанию: Параметру procent в приведенном выше примере было присвоено значение 10. Это означает, что если при вызове процедуры параметр procent не был указан, то он будет приравнен к 10. Секция объявлений в процедуре располагается между служебным словом AS и началом выполняемой секции, то есть словом BEGIN. Служебное слово DECLARE при этом, в отличие от секции объявлений анонимного блока и секции объявлений в триггере, НЕ УКАЗЫВАЕТСЯ. Например: CREATE OR REPLACE PROCEDURE temp AS s varchar(50); BEGIN dbms_output.put_line(s); END; / Процедура может содержать только операторы DML, управляющие конструкции и вызовы процедур и функций. В процедуре нельзя использовать операторы DDL в число которых входят CREATE, ALTER, DROP. Начиная с версии 8i в ORACLE появилась возможность обойти это "неудобство" вызовом специальной процедуры IMMEDIATE. Например внутри базового блока PL/SQL можно написать конструкцию следующего вида: ... EXECUTE IMMEDIATE 'create table test(id number);' ... Но для того, чтобы вызвать функцию create table (или какую-либо другую) в качестве параметра, необходимо обладать соответствующей прямой привилегией. Например, чтобы вышеприведенный пример заработал, необходимо, чтобы администратор базы данных выдал вам привилегию CREATE TABLE, несмотря на то, что вы уже обладаете ролью RESOURCE, в которую входит данная привилегия. Вызов процедур: Для вызова процедур используется оператор execute или exec. Например: execute increase_prices(5); или execute increase_prices; Во втором случае процедуре не передается входной параметр, поэтому при выполнении процедуры он будет равен значению по умолчанию. Вызов процедуры можно производить не только из среды SQL Plus, но и, естественно, внутри других процедур, функций или триггеров. Удаление процедур: Для удаления процедуры необходимо выполнить оператор DROP PROCEDURE имя_процедуры |
10. ФУНКЦИИ |
Функции отличаются от процедур тем, что возвращают какое-то значение и вызываются только из других предложений SQL. Синтаксически это отличие отражено в спецификации функции. В остальном, функция создается по тем же правилам, что и процедура. Например, оператор создания функции, возвращающей максимальную цену среди всех товаров может выглядеть следующим образом: CREATE FUNCTION get_max_price RETURN NUMBER AS Max_price NUMBER; BEGIN SELECT max(value) INTO max_price FROM prices; RETURN max_price; END; / Заметьте, что в спецификации функции присутствует служебное слово RETURN, после которого указывается тип возвращаемого значения. Размер типа возвращаемого значения также как и размер типа входных и выходных параметров не должен быть конкретизирован. В секции объявлений объявлена одна переменная max_price типа NUMBER, которая используется для хранения максимальной цены, которую возвращает запрос. Для возврата значения из функции в вызвавшее ее SQL предложение используется оператор RETURN. Также стоит отметить некоторое отличие в синтаксисе оператора SELECT, а именно присутствие служебного слова INTO. Внутри процедур, функций и триггеров нельзя использовать оператор SELECT без служебного слова INTO. После INTO в запросе должна быть указана одна или несколько переменных, в которые и запишутся результаты выполнения запроса. Естественно, что эти переменные должны быть предварительно объявлены в секции объявлений. Вызов функций: Как уже было отмечено выше, функции, в отличие от процедур, не могут вызываться при помощи оператора execute, они всегда являются частью более сложного SQL-оператора. Например: Exec increase_prices(get_max_price/100); Здесь функция является частью более сложного оператора (в данном случае вызова процедуры). Во время отладки функции для проверки ее работоспособности используется следующая конструкция: SELECT имя_функции(входные_параметры) FROM DUAL; Удаление функций: Удаление функция производится посредством оператора DROP FUNCTION имя_функции; |
11. УПРАВЛЯЮЩИЕ СТРУКТУРЫ В PL/SQL |
PL/SQL дает возможность выполнять условную и итеративную обработку. Предоставляемые им конструкции изменяют ход выполнения программы (program flow), управляя последовательностью выполнения (flow of execution). Оператор IF Оператор IF имеет следующий синтаксис: IF условие_1 THEN действие_1; [ELSIF условие_2 THEN действие_2;] ... [ELSE альтернативное_действие;] END IF; Действие_1 ... альтернативное_действие представляют один или несколько PL/SQL операторов. Каждая группа выполняется только в том случае, если выполнено соответствующее условие. После того, как обнаружено выполнение одного из условий, остальные условия не проверяются. Циклы LOOP PL/SQL предоставляет три различные конструкции для итеративной обработки. Каждая из них позволяет циклически выполнять набор операторов PL/SQL. Выход из цикла осуществляется в зависимости от некоторого условия. Конструкция цикла LOOP имеет следующий синтаксис: <<имя_цикла>> LOOP операторы; EXIT имя_цикла [WHEN условие_выхода]; операторы; END LOOP; При наличии конструкции WHEN все операторы в теле цикла повторяются до тех пор, пока выражение условие_выхода не станет истинным. В этом случае все операторы, находящиеся после EXIT пропускаются, итерации прекращаются и выполнение продолжается с первого оператора, идущего за END LOOP. Циклы WHILE Еще одной разновидностью циклов является цикл WHILE. Он хорошо подходит в ситуациях, когда количество итераций заранее неизвестно, и определяется некоторым внешним фактором. Цикл WHLE имеет следующий синтаксис: WHILE условие_продолжения_цикла LOOP операторы; END LOOP Пример использования цикла WHILE: DECLARE just_a_num NUMBER := 1; BEGIN WHILE (just_a_num<=10) LOOP dbms_output.put_line(just_a_num); just_a_num:=just_a_num+1; END LOOP; END; / Не забудьте перед вводом данного примера установить настройку сессии set serveroutput on. Циклы FOR В цикле FOR для подсчета итераций используется переменная-счетчик, называемая также индексом цикла (loop index). По завершении каждой итерации счетчик увеличивается, начиная с нижнего предела, или уменьшается, начиная с верхнего предела. Как только его значение выйдет за указанный диапазон, цикл завершается. Синтаксис цикла FOR выглядит следующим образом: FOR счетчик IN [REVERSE] нижняя_граница .. верхняя граница LOOP операторы; END LOOP; |
12. ДИНАМИЧЕСКИЕ ТИПЫ ДАННЫХ И ЗАПИСИ PL/SQL |
Записи PL/SQL позволяют собирать разные элементы данных в одно целое и тем самым скрывать сложность этих данных. Кроме того, передавать несколько переменных менее удобно, чем использовать одну запись, поля которой могут содержать информацию сразу из всех ваших переменных. Этот принцип аналогичен принципу контейнерных перевозок, совершившему переворот в транспортной индустрии. Каждый контейнер может вмещать множество товаров, транспортируемых как одно целое. Когда вам нужно поменять ассортимент товаров, достаточно открыть контейнер и поместить объект внутрь или вынуть наружу. В работе крана, переносящего контейнер с места на место, в этом случае ничего менять ничего не нужно. Подобно этому спецификация программного модуля PL/SQL не обязательно должна меняться при изменении структуры записи. В приведенном ниже примере процедура newDealer в качестве параметров принимает два значения: имя дилера и процент от сделки, который он будет получать в качестве прибыли: DECLARE PROCEDURE newDealer( newname varchar, newprocent number) AS BEGIN insert into dealers values(dealers_seq.NEXTVAL, newname, newprocent); END;
BEGIN newDealer(`Василий Иванович`, 15); END; / А если представить, что передаваемых параметров не два, а 10? Тогда и вызов процедуры и сама спецификация процедуры значительно усложняется. А где возрастает сложность, там возрастает и вероятность возникновения ошибки. В данном примере продемонстрирована возможность создания и использования внутренних процедур. Подобные процедуры и функции описываются как обычные переменные в секции объявлений базового блока, но уже без использования слов CREATE OR REPLACE. Такие процедуры и функции доступны для вызова только из того базового блока, в котором описаны. Что касается самого базового блока, то, как говорилось в разделе 1 ("Базовый блок PL/SQL"), базовые блоки могут быть вложены друг в друга, например следующим образом: declare m number:=1; begin if m>0 then declare procedure show as begin dbms_output.put_line(m); end; begin show; end; end if; end; / В этом примере небольшой базовый блок, включающий в свою очередь внутреннюю процедуру, включен внутрь основного базового блока. Используя записи PL/SQL, предыдущий пример можно переписать следующий образом: DECLARE type Tdealer IS RECORD( name varchar(50), procent number(4,2)); d Tdealer;
PROCEDURE newDealer( newdealer Tdealer) AS BEGIN insert into dealers values(dealers_seq.NEXTVAL, newdealer.name, newdealer.procent); END;
BEGIN d.name:=`Василий Иванович`; d.procent:=15; newDealer(d); END; / Здесь использована запись PL/SQL. Сначала объявляется тип записи Tdealer. Затем объявляется переменная этого типа, после чего она используется в выполняемой секции. Теперь, чтобы передать данные процедуре, не нужно перечислять все параметры через запятую, а достаточно передать лишь одну переменную типа запись, которая содержит внутри себя все поля. Для создания записи используется следующий синтаксис: TYPE имя_типа_записи IS RECORD (имя_поля_1 тип_поля_1, имя_поля_2 тип_поля_2, ... ); Еще одно важное значение записей - это применение в операторе SELECT INTO. Как известно, запрос, находящийся внутри исполняемой секции базового блока должен возвращать результат в переменную или список переменных. Список переменных, в данном случае, может быть заменен на одну переменную типа запись. Например: DECLARE TYPE Tdealer IS RECORD( name varchar2(50), procent number(4,2) ); d Tdealer;
FUNCTION getDealerInfo(d_id number) RETURN Tdealer AS tempD Tdealer; BEGIN select name,procent INTO tempD from dealers where dealer_id=d_id; RETURN tempD; END;
BEGIN d:=getDealerInfo(1); dbms_output.put_line(d.name); dbms_output.put_line(d.procent); END; / Динамические типы данных: Представьте теперь, что вам нужно создать запись, поля которой совпадают со столбцами таблицы; или переменную, имеющую тот же тип, что и столбец таблицы; или запись, поля которой совпадают со столбцами, выбранными курсором. PL/SQL предоставляет все необходимые для этого средства:
Предыдущий пример с процедурой newDealer можно переписать следующим образом: DECLARE d managers%ROWTYPE;
PROCEDURE newDealer( newdealer managers%ROWTYPE) AS BEGIN insert into dealers values(dealers_seq.NEXTVAL, newdealer.name, newdealer.procent); END;
BEGIN d.name:=`Василий Иванович`; d.procent:=15; newDealer(d); END; / Здесь была использована возможность объявления переменной динамического, или привязанного (anchored), типа, что еще более упрощает ситуацию с использованием записей. |
13. КУРСОРЫ |
Курсор - это исключительно важная конструкция PL/SQL, лежащая в основе взаимодействия PL/SQL и SQL. Курсор - это указатель на набор записей, полученный в результате выполнения связанного с ним оператора SELECT. Используя курсор, можно отдельно обрабатывать каждую строку набора данных, возвращаемого связанным с ним SQL-оператора. Курсор, как и переменная, объявляется в секции объявлений базового блока. Синтаксис объявления курсора следующий: CURSOR имя_курсора [(параметр_1 [, параметр_2, ...])] [RETURN спецификация_возврата] IS оператор_SELECT [FOR UPDATE [OF таблица_или_столбец_1 [, таблица_или_столбец_2, ...] ] ] Параметры курсора - это то же, что и параметры процедуры или функции, за тем исключением, что они всегда являются входными (IN). Значения переданных параметров могут использоваться в разделе WHERE связанного с курсором оператора SELECT. Вся работа с курсором производится в следующей последовательности:
Использование команд OPEN, FETCH и CLOSE Команды открытия курсора, выборки данных из курсора и закрытия курсора имеют следующий синтаксис: OPEN имя_курсора [(параметр_1 [, параметр_2 ...])]; FETCH имя_курсора INTO переменная_список_переменных_или_запись; CLOSE имя_курсора; В момент открытия оператором OPEN курсор выполняет связанный с ним оператор SELECT. Если оператор SELECT возвращает непустой набор записей курсор автоматически указывает на первую выбранную строку. При этом, если в объявлении курсора присутствуют служебные слова FOR UPDATE, курсор блокирует указанные таблицы и/или строки. Каждая команда FETCH перемещает данные из курсора в указанные переменные, после чего перемещает указатель на следующую запись в наборе записей, возвращенным оператором SELECT. Если записей больше нет, указатель все время будет указывать на последню запись, а атрибуты курсора %FOUND и %NOTFOUND становятся равными, соответственно, FALSE и TRUE. При выполнении оператора CLOSE курсор закрывается. При этом освобождаются все ресурсы, занятые во время открытия курсора, а также разблокируются таблицы и столбцы, если они были блокированы при открытии курсора. Атрибуты курсора: Курсор имеет ряд индикаторов, показывающих его состояние. Они называются атрибутами курсора.
Перед тем, как попытаться выбрать из курсора очередные данные, следует проверить состояние атрибутов %FOUND или %NOTFOUND. Фактическая обработка записей из курсора обычно выполняется внутри цикла. При написании такого цикла обычно производится проверка, была ли найдена хотя бы одна запись. Если да, то можно продолжить обработку этой записи; в противном случае следует выйти из цикла. Пример: set serveroutput on
DECLARE -- объявление курсора CURSOR showmanagers IS select * from managers; -- объявление временной переменной для хранения текущей строки курсора m managers%ROWTYPE; BEGIN
-- открытие курсора OPEN showmanagers; -- выборка первой записи FETCH showmanagers INTO m;
-- продолжать цикл до тех пор, пока курсор указывает на необработанную запись WHILE showmanagers%FOUND LOOP dbms_output.put_line(to_char(showmanagers%ROWCOUNT)||` `||m.name); -- выбрать следующую запись FETCH showmanagers INTO m; END LOOP; END; / Приведенный пример выводит на экран пронумерованный список имен менеджеров. Курсорный цикл FOR Приведенный выше пример можно реализовать другим, более кратким путем, используя курсорный цикл FOR. При этом PL/SQL будет осуществлять открытие, выборку и закрытие курсора без вашего участия. Синтаксис курсорного цикла FOR имеет следующий вид: FOR запись_курсора IN имя_курсора[(параметр_1 [, параметр_2 ...])] LOOP операторы; END LOOP; Этот цикл выбирает записи из курсора в переменную типа запись_курсора. Поля записи_курсора можно использовать для доступа к данным из операторов PL/SQL, выполняемых в цикле. Когда все записи выбраны, цикл завершается. Для удобства, открытие и закрытие курсора происходит автоматически. Пример: DECLARE -- объявление курсора CURSOR showmanagers IS select * from managers;
BEGIN FOR m IN showmanagers LOOP dbms_output.put_line(to_char(showmanagers%ROWCOUNT)||` `||m.name); END LOOP; END; / Данный пример делает то же, что и предыдущий, но даже на первый взгляд видно, что он значительно короче и проще. Уже не нужно объявлять переменную для временного хранения текущей строки курсора. Не надо открывать или закрывать курсор. Конструкция WHERE CURRENT OF Когда курсор открывается для обновления или удаления выбранных записей, можно использовать конструкцию WHERE CURRENT OF имя_курсора для доступа к таблице и строке, которые соответствуют текущей строке курсора. В приведенном ниже примере цены на все товары, срок хранения которых истечет через три дня, снижаются на 3%: DECLARE -- объявление курсора CURSOR allprices IS select value from prices p1, products p2 where p1.pr_id=p2.pr_id and dayfrom<=SYSDATE and dayto>=SYSDATE and expire_time<=SYSDATE+3 for update of value;
BEGIN FOR price IN allprices LOOP update prices set value=(price.value * 0.97) WHERE CURRENT OF allprices; END LOOP; END; / Оператор SELECT, связанный с курсором, выбирает цены только на те товары, срок годности которых истечет менее, чем через три дня. Потом в цикле все отобранные значения уменьшаются на заданную величину. Задачу, которую выполняет данный пример, можно выполнить и без применения курсора, но в данном случае он приведен в учебных целях. |
14. ИСКЛЮЧЕНИЯ |
Цель применения исключений в ORACLE - выдача дружественных к пользователю сообщений об ошибках. Исключение (исключительная ситуация) - это такая ситуация, которая возникает или активизируется в ходе выполнения программы, когда дальнейшее выполнение программы не имеет смысла. Исключительная ситуация это не всегда ошибка с точки ORACLE. Часто это ошибка только с точки зрения информационной системы. Реакция программы на возникновение исключительной ситуации описывается в обработчиках исключительных ситуация в секции исключений (exception section). Если при возникновении исключительной ситуации в секции исключений не находится соответствующего обработчика, то ORACLE обрабатывает его "своими силами". Секция исключений, предназначенная для обработки исключений, - это идеальное место для выдачи информативных сообщений об ошибках и выполнения очистки (cleanup), позволяющей избавиться от всего, что могло бы в дальнейшем вызвать путаницу или проблемы. Если исключение было активизировано в ходе выполнения процедуры, вставляющей строки в таблицу, то типичная процедура очистки может включать в себя оператор ROLLBACK. После того, как управление было передано обработчику исключения, оно уже не возвращается оператору, ставшему причиной этого исключения, то есть работа секции выполнения прекращается. Исключение может активизироваться либо системой, либо самим пользователем. В первом случае исключения называют системными, во втором - пользовательскими.
|
14.1. СИСТЕМНЫЕ ИСКЛЮЧЕНИЯ |
Существуют стандартные проблемы и, соответственно, стандартные исключения. Несколько из них привидены в таблице:
Обработчики исключений пишутся в конце базового блока (перед END) в секции исключений, которая начинается со служебного слова EXEPTION. Для обработки конкретного исключения указываются служебные слова WHEN, после которого идет название исключения, и слово THEN, после которого идет код обработчика указанного исключения. Если обработчиков исключений несколько, то для каждого из них используется такая же конструкция: ... EXCEPTION WHEN имя_исключения_1 THEN операторы_обрабатывающие_исключение имя_исключения_1 [WHEN имя_исключения_2 THEN операторы_обрабатывающие_исключение имя_исключения_2 WHEN ... ] Пример 1: DECLARE a number:=6; b number:=0; begin a:=a/b; b:=7; dbms_output.put_line(`b=`||b); EXCEPTION WHEN ZERO_DIVIDE THEN dbms_output.put_line(`Не удалось выполнить операцию деления`); dbms_output.put_line(`a=`||a||`, b=`||b); END; / При обработке исключений можно использовать две специальные переменные - SQLCODE и SQLERRM. Первая содержит код ошибки, вторая - имя и описание ошибки. Пример 2: DECLARE a number:=6; b number:=0; begin a:=a/b; b:=7; dbms_output.put_line(`b=`||b); EXCEPTION WHEN ZERO_DIVIDE THEN DECLARE enum number:=SQLCODE; emsg varchar2(512):=SQLERRM; BEGIN dbms_output.put_line(`ORA Error NUM: `||enum); dbms_output.put_line(`ORA Error MSG: `||emsg); dbms_output.put_line(`a=`||a); dbms_output.put_line(`b=`||b); END; END; / |
14.2. ПОЛЬЗОВАТЕЛЬСКИЕ ИСКЛЮЧЕНИЯ |
Пользователь может создавать и собственные исключения, которые система не обнаруживает и не считает за ошибки. Например, попытка вставить в поле КОЛИЧЕСТВО отрицательную величину. Исключения, определяемые пользователем описываются аналогично переменным в секции объявления, но только с типом EXCEPTION. Вызываются, или активизируются, исключения оператором RAISE, после которого идет название исключения. Пример: DECLARE quantity_must_positive EXCEPTION; BEGIN ... IF (quantity<0) then RAISE quantity_must_positive; END IF; ... EXCEPTION WHEN quantity_must_positive THEN dbms_output.put_line(`Количество не может быть отрицательной величиной`); ... END; / Оператор RAISE_APPLICATION_ERROR Собственное исключение можно активировать также, используя команду RAISE_APPLICATION_ERROR(ERNUM,ERMESSAGE), где ERNUM - номер ошибки (от -20000 до -20999), а ERMESSAGE - текст сообщения об ошибке. Данный способ более предпочтителен, чем вывод сообщения с помощью dbms_output.put_line, если сообщение об ошибке нужно вернуть в вызвавшее процедуру или функцию внешнее приложение, написанное на языке высокого уровня. Применение dbms_output.put_line резонно лишь в том случае, когда функция или процедура вызывается из среды SQL Plus, то есть для отладочных целей во время разработки. Во время же эксплуатации готовой системы все сообщения, выводящиеся на экран посредством dbms_output.put_line просто не дойдут до пользователя. Пример: DECLARE quantity_must_positive EXCEPTION; BEGIN ... IF (qiantity<0) then RAISE_APPLICATION_ERROR(-20001,`Количество не может быть отрицательной величиной`); END IF; ... END; / В этом случае, поскольку обработчика исключительной ситуации нет, управление никуда передаваться не будет, просто завершится выполение базового блока, в котором произошло исключение. В приложении, которое вызвало процедуру или функцию, содержащие данный базовый блок, можно обработать это исключение. |
16. ПАКЕТЫ PL/SQL |
Почему с персональным компьютером так легко работать? Отчасти потому, что в нем множество полезных функций объединено в один простой в использовании пакет. Программное обеспечение показывает окна (формы), и для достижения желаемого результата не нужно знать, каким образом щелчок мыши передается в компьютер. Сложность "закадровой" деятельности скрыта от пользователя, которому достаточно знать лишь о том, что определенное действие с его стороны приведет к предсказуемым результатам. При разработке приложений PL/SQL обеспечивает похожий эффективный подход, представляя пакеты (packages) для совместного хранения полезных функций, процедур, типов записей и курсоров. Аналогично процедуре или функции, пакет имеет спецификацию и тело. Однако спецификация и тело пакета создаются отдельно друг от друга. Можно даже заменить одно тело пакеты другим, сохранив совместимость с существующей спецификацией, и пакет по-прежнему будет работать. Так зачем нужно держать тело отдельно от спецификации? Все очень просто. Пользователи пакета не обязаны знать все детали его реализации, поэтому эти детали скрываются внутри тела (инкапсуляция). Тело хранится, компилируется и обрабатывается внутри базы данных и невидимо пользователям пакета. Для программирования своих задач им просто следует пользоваться спецификацией. Это очень важно, когда вы хотите защитить свой код, сделав его недоступным для хакеров или конкурентов. Если проводить аналогию с объектно-ориентированным программированием (ООП), то пакет внешне очень напоминает класс, у которого также спецификация и реализация разделены между собой. При создании и использовании пакетов используется один из принципов ООП - Инкапсуляция, то есть скрытие реализации, о чем уже говорилось в предыдущем параграфе. Вызов процедур и функций, входящих в состав пакета Вызов процедур и функций, входящих в состав пакета, также внешне сильно напоминает вызов методов класса. Например, для вызова процедуры increase_prices, входящей в состав пакета prices, нужно выполнить следующий оператор: exec prices.increase_prices; То есть для обращения к процедурам, переменным и функциям пакета используется нотация очень похожая на использование методов и свойств класса: имя_пакета.объект_пакета. Вы уже знакомы с функцей put_line поставляемого ORACLE пакета dbms_output. Если внутри пакета необходимо сослаться на собственный объект пакета, то, естественно, нет необходимости указывать имя пакета перед именем объекта (опять же, как и в методах класса). В спецификации пакетов можно указывать не только входящие в его состав процедуры и функции, но и переменные, которые в классе назывались бы свойствами класса. Эти переменные являются общими для всех процедур и функций, входящих в состав пакета. Создание спецификации пакета: CREATE PACKAGE имя_пакета IS [объявления_переменных_и_типов] [спецификации_курсоров] [спецификации_функций_и_процедур] END [имя_пакета]; / Все переменные и типы, объявленные в спецификации пакета, доступны его пользователям. Спецификация позволяет узнать, что содержит пакет. Опять же, если проводить аналогию с ООП, спецификация - это интерфейс пакета. Переменные, присутствующие в спецификации пакета, называются переменными пакета (package variables). Они инициализируются только один раз - при первом обращении к нему. Когда производится вызов какой-либо составляющей пакета, ORACLE загружает пакет в память, где он и остается все то время, пока пользователь соединен с базой данных. При наличии нескольких сеансов переменные пакета и их значения становятся разделяемыми; следует также заметить, что обращение к объектам пакета в последующих сеансах происходит быстрее, поскольку пакет уже присутствует в памяти сервера. Создание тела пакета: CREATE OR REPLACE PACKAGE BODY имя_пакета IS [локальные_переменные] [полные_спецификации_курсоров_пакета] [полные_спецификации функций_и_процедур_пакета] BEGIN [выполняемые_операторы] [EXCEPTION] [обработчики_исключений] END [имя_пакета]; / Выполняемая секция пакета обычно используется для инициализации локальных переменных пакета или переменных пакета. Она соответствует конструктору класса в ООП. Выполнение этой секции производится один раз при загрузке пакета, а следовательно, ее не стоит использовать для каких-либо повторяющихся действий, поскольку обратиться к ней более одного раза все равно не удастся. Пример создания и использования пакета В приведенном ниже примере будет создан пакет, в котором собраны функции и процедуры, связанные с таким объектом информационной системы, как менеджер. Далее будут приведены пояснения и комментарии к этому примеру. create or replace package manager is -- переменная, содержащая текущее количество менеджеров count number;
-- прототип функции, возвращающей информацию -- о лучшем менеджере фирмы function best RETURN managers%ROWTYPE;
-- прототип процедуры, удаляющей менеджера procedure del(manr_id number); END manager; /
create or replace package body manager is
-- функция возвращает менеджера, получившего наибольшее -- количество прибыли function best RETURN managers%ROWTYPE AS m managers%ROWTYPE; BEGIN select * INTO m FROM managers WHERE manager_id=1; RETURN m; END;
-- процедура удаления менеджера procedure del(man_id number) AS mcount number; BEGIN select manager_id INTO mcount FROM managers WHERE manager_id=man_id; delete from outgoing where manager_id=man_id; delete from incoming where manager_id=man_id; delete from managers where manager_id=man_id; EXCEPTION WHEN NO_DATA_FOUND THEN Raise_Application_Error (-20001, `Such manager is not found`); END;
-- функция возвращает текущее количество менеджеров -- (функция видна только из методов пакета) function mCount RETURN number AS m number; BEGIN select count(*) into m from managers; RETURN m; END;
-- при инициализации пакета в переменную count помещается -- текущее число менеджеров BEGIN count:=mCount; END; / В спецификации данного пакета указана одна переменная, одна функция и одна процедура. Это то, что видно "снаружи", то есть то, что может использовать пользователь в своей работе с этим пакетом (примеры использования данного пакеты приведены ниже). Выполняемая секция (execution section) тела пакета содержит одно SQL предложение, цель которого поместить в переменную count текущее количество менеджеров в информационной системе. Данное предложение будет вызвано всего лишь один раз при любом первом обращении к любому из объектов пакета, поэтому вряд ли значение переменной count всегда будет актуально, но в данном случае она использована в учебных целях. Значение переменной count приравнивается результату выполнения функции managersCount, которая не видна "снаружи", а доступна только из процедур и функций самого пакета. Тип managers%ROWTYPE в описании прототипа функции bestManager означает, что тип возвращаемого функцией значения зависит от текущей структуры таблицы managers. Данный тип называется динамической записью и помогает создать определенную гибкость в работе с объектами информационной системы. Если посмотреть на реализацию функции bestManager, то станет понятно, зачем это было сделано. Даже при изменении стуктуры таблицы - удалении или добавлении полей - функция bestManager будет работать правильно. В реализации процедуры удаления менеджера показан пример использования исключения. Если при вызове процедуры будет указан номер несуществующего менеджера, то при попытке определить номер менеджера в первом операторе процедуры возникнет исключительная ситуация NO_DATA_FOUND, обработчик которой находится в секции исключений. В этом случае работа процедуры прекратится и на экран выдастся сообщение об ошибке `Such manager is not found`. В качестве первого параметра функции RAISE_APPLICATION_ERROR, содержащего номер ошибки, можно указывать любое число в пределах от -20000 до -20999. Последующие три оператора DELETE удаляют из базы данных всю информацию, как-то связанную с указанным менеджером. Поскольку между таблицами MANAGERS, INCOMING и OUTGOING существуют связи, удаление информации нужно производить именно в таком порядке: сначала из дочерних таблиц, а затем из родительской. Использование пакета: Для того, чтобы вывести на экран текущее количество менеджеров, то есть значение переменной count пакета doManagers, можно поступить следующим образом: begin dbms_output.put_line(manager.count); end; / Для того, чтобы вывести на экран имя самого удачливого менеджера, можно написать, например, блок такого вида: declare m managers%ROWTYPE; begin m:=manager.best; dbms_output.put_line(m.name); end; / |
17. ТРИГГЕРЫ |
Триггер - это особого вида процедура, которая выполняется автоматически при возникновении некоторого события, указанного в спецификации триггера, - триггерного события (triggering event). В PL/SQL можно создать триггеры, которые будут срабатывать в одной из следующих ситуаций:
Между триггерами и обычными процедурами PL/SQL есть три различия:
Сходство между триггерами и процедурами состоит в следующем:
Триггеры представляют собой весьма мощные инструменты. Однако их следует использовать аккуратно, поскольку триггер может срабатывать при каждом обращении к таблице, тем самым увеличивая нагрузку на сервер базы данных. Разумное практическое правило состоит в том, чтобы использовать триггер только для действий, которые нельзя выполнить другими средствами. Например, если есть возможность создать одно или несколько ограничений, выполняющих работу некоторого триггера, следует использовать эти ограничения. Если итоговые величины допустимо вычислять в нерабочее время, систему лучше спроектировать именно так, а не использовать триггеры, срабатывающие при каждой транзакции. Предположим, например, что банк принимает решение о доставке дополнительной наличности из центрального хранилища в зависимости от того, сколько 20-долларовых банкнот было выдано за текущий день. Эту величину можно определять по окончании рабочего дня. Если же для обновления счетчика 20-долларовых банкнот будет использоваться триггер, то его постоянное срабатывание может существенно замедлить скорость выполнения транзакций в рабочие часы. Триггеры, определенные для таблиц, называются табличными триггерами (table triggers). Далее речь пойдет именно о них. Синтаксис создания триггера имеет следующий вид: CREATE OR REPLACE TRIGGER имя_триггера момент_срабатывания триггерное_событие ON имя_таблицы_или_представления [WHEN триггерное_ограничение] [FOR EACH ROW] [DECLARE объявления] BEGIN Операторы [EXCEPTION WHEN имя_исключения THEN …] END имя_триггера; Типы триггеров Момент_срабатывания определяет, когда будет срабатывать триггер: до (BEFORE), после (AFTER) и вместо (INSTEAD OF) наступления триггерного события (выполнения запускающего оператора). Если указано значение BEFORE, триггер выполняется до каких-либо проверок ограничений на строки, затрагиваемые триггерным событием. Никакие строки не блокируются. Триггер этого типа называется, соответственно, BEFORE-триггером (BEFORE trigger). Если выбрать ключевое слово AFTER, то триггер будет срабатывать после того, как запускающий оператор завершит свою работу и будут выполнены проверки всех ограничений. В этом случае затрагиваемые строки блокируются на время выполнения триггера. Триггер этого типа называется AFTER-триггером (AFTER trigger). Триггеры INSTEAD OF применяются только для представлений (VIEW). Проблема состоит в том, что операторы DML не применимы к представлениям. Нельзя добавлять, изменять или удалять записи из представлений. Триггеры INSTEAD OF вызываются вместо выполнения DML-выражений. Если вы выполните оператор DML к представлению, то в соответствующем триггере можно выполнить какие-либо действия, и тогда у пользователя создастся впечатление, что он работает с таблицей. Триггерное_событие может принимать значения INSERT, UPDATE или DELETE. Триггерное_ограничение - это одно из дополнительных ограничений, которые должны быть выполнены для срабатывания триггера. Необязательный набор ключевых слов FOR EACH ROW указывает на необходимость выполнять тело триггера для каждой строки, затрагиваемой запускающим оператором. Такие триггеры называются строчными (row triggers). Если опция FOR EACH ROW отсутствует, то при наступлении триггерного события триггер выполнится только один раз. В этом случае он называется операторным триггером (statement trigger), поскольку выполняется только один раз для каждого запускающего оператора. Часть кода между DECLARE и END имя_триггера представляет собой обычный базовый блок PL/SQL. Различным триггерные события можно комбинировать с помощью оператора OR. Например: DELETE OR INSERT остальные_операторы В случае использования UPDATE можно указать список столбцов, при изменении которых будет срабатывать триггер: UPDATE OF столбец_1, столбец_2, ... При использовании UPDATE в операторах PL/SQL обращение к новой и старой строкам выполняются с помощью слов "new" и "old", предваренных двоеточием. Так, :old.имя_столбца даст значение, которое столбец имел до обновления. Однако в триггерном ограничении имена "old" и "new" используются без двоеточий. ВАЖНО!!! Триггерные ограничения, а также корреляционные имена new и old, могут использоваться только в строчных триггерах. Корреляционное имя new имеет смысл использовать только в триггерах на INSERT и UPDATE, поскольку в триггерах на DELETE никакого нового значения полей нет. Тоже самое можно сказать и о корреляционном имени old, значение которого определено только для триггеров, сработавших на UPDATE и DELETE. Одна очень важная особенность корреляционного имени new для строчных BEFORE-триггеров: значения полей корреляционного имени new можно менять в строчных BEFORE-триггерах. Например, если в триггере BEFORE INSERT проверяется значение поля добавляемой строки и оно по каким-то соображениям не удовлетворяет необходимым условиям информационной системы, его (значения поля) можно изменить, применив оператор присваивания непосредственно к корреляционному имени new: IF :new.procent>50 then :new.procent:=50; END IF; Если триггер срабатывает сразу на несколько событий, то чтобы определить на какое из указанных событий он сработал, можно внутри исполняемой секции триггера использовать условные предикаты INSERTING, UPDATING и DELETING. Первый из них равен TRUE, когда триггер сработал на INSERT, второй - на UPDATE, третий - на DELETE. Пример триггера Триггер, который будет запрещать изменение имени менеджера (поле NAME). CREATE OR REPLACE TRIGGER onManagersUpdate BEFORE UPDATE OF name ON Managers FOR EACH ROW DECLARE cant_change_name EXCEPTION; BEGIN IF :new.name<>:old.name THEN RAISE cant_change_name; END IF; EXCEPTION WHEN cant_change_name THEN dbms_output.put_line(`Нельзя изменить имя менеджера`); :new.name:=:old.name; END; / Данный триггер не позволит изменить значение поля NAME в таблице MANAGERS. При попытке сделать это сработает триггер, внутри которого производится сравнение старого значения и нового значения поля NAME. Если они различаются, то активизируется исключение, при обработке которого на экране появится соответствующее сообщение. В данном случае использована одна очень важная особенность BEFORE-триггеров: если в BEFORE-триггере возникает исключение, то SQL-предложение, вызвавшее триггер, не выполнится. Удаление триггеров, также как и удаление всех остальных объектов СУБД Oracle, осуществляется посредством оператора DROP: DROP имя_триггера; Если по каким-то причинам триггер нужно на время отключить, то это можно сделать при помощи команды ALTER TRIGGER имя_триггера DISABLE; Обратное включение триггера осуществляется при помощи команды ALTER TRIGGER имя_триггера ENABLE; Поскольку с одной таблицей могут быть связаны несколько триггеров, то бывает необходимо отключить сразу все эти триггеры. Это делается при помощи команды ALTER TABLE имя_таблицы DISABLE ALL TRIGGERS; Включение всех триггеров осуществляется командой ALTER TABLE имя_таблицы ENABLE ALL TRIGGERS; Вывод информации о триггерах Например, предположим, что для создания триггера REORDER было использовано следующее предложение: CREATE TRIGGER reorder AFTER UPDATE OF parts_on_hand ON inventory FOR EACH ROW WHEN (new.parts_on_hand < new.reorder_point) DECLARE x NUMBER; BEGIN SELECT COUNT(*) INTO x FROM pending_orders WHERE part_no = :new.part_no; IF x = 0 THEN INSERT INTO pending_orders VALUES (:new.part_no, :new.reorder_quantity, sysdate); END IF; END; Следующие два запроса возвращают информацию о триггере REORDER: SELECT type, triggering_statement, table_name FROM user_triggers WHERE name = `REORDER`;
SELECT trigger_body FROM user_triggers WHERE name = `REORDER`; |
18.3. ФИЛЬТРАЦИЯ И ПОИСК В НАБОРАХ ДАННЫХ |
Фильтрация - это задание дополнительных ограничений для записей, отбираемых в набор данных (компоненты TTable и TQuery). Фильтр позволяет управлять только видимостью записей. Если какая-то записть не удовлетворяет условию фильтра, то она все равно передается на клиентский компьютер, но там она не показывается. Возникает вопрос, зачем нужно задавать ограничения с помощью фильтров Delphi, если можно задать ограничения в запросе? Дело в том, что, например, для компонента TTable никаких ограничений, кроме как с помощью фильтра Delphi, задать нельзя. А во-вторых, фильтрация записей происходит на клиентском комьютере и для этого не нужно посылать дополнительный запрос на сервер. Delphi позволяет осуществлять фильтрация записей:
Фильтрация по выражению Для задания выражения фильтра используется свойство Filter типа String. Фильтр представляет собой конструкцию, в состав которой могут входить следующие элементы:
Если имя поля содержит пробелы, то его заключают в квадратные скобки, в противном случае квадратные скобки необязательны. Литерал представляет собой значение, заданное явно, например, число, строка или символ. Операциии сравнения представляют собой обычные отношения >, <, =, <=, >= и <>. Арифметическими являются операции +, -, * и /. В качестве логических операция можно использовать AND, OR и NOT. Круглые скобки применяются для изменения порядка выполнения арифметических и логических операций. Пример фильтрации по выражению: Procent>=20 Name=`* Александр` OR Name=`* Алексей` Из последнего примера видно, что при задании фильтра можно использовать специальный символ "*", означающий возможное наличие любого числа любых символов в том месте, где он указан. Для активизации и обратной деактивизации фильтра применяется свойство Filtered типа boolean. Для включения фильтрации этому свойству необходимо приравнять значение true. Для фильтрации возможно задание двух параметров в свойстве FilterOptions:
По умолчанию все параметры фильтра выключены, и свойство FilterOptions имеет значение []. Фильтрация по диапазону При фильтрации по диапазону в набор записей включаются записи, значения полей которых попадают в заданный диапазон, т.е. условием фильтрации является выражение вида значение > нижней границы AND значение < верхней границы. Такая фильтрация применяется к наборам данных TTable. Достоинством фильтрации по диапазону является высокая скорость обработки записей. В отличие от фильтрации по выражению, когда последовательно просматриваются все записи таблицы, фильтрация по диапазону ведется индексно-последовательным методом, поэтому этот способ фильтрации применим только для индексированных полей. Индекс поля, диапазон которого задан в качестве критерия для отбора записей, должен быть установлен как теущий с помощью свойства IndexName или IndexFieldNames. Если текущий индекс не установлен, то по умолчанию используется главный индекс. Для включения и выключения фильтрации по диапазону применяются методы ApplyRange и CancelRange. Первый из них активизирует фильтр, а второй - деактивизирует. Предварительно для индексного поля (полей), по которому выполняется фильтрация, следует задать диапазон допустимых значений. Методы SetRangeStart и SetRangeEnd устанавливают нижнюю и верхнюю границу диапазона, соответственно. Названные процедуры не имеют параметров, и для задания границ диапазона используется просто оператор присваивания. Для изменения предварительно установленных границ диапазона предназначены методы EditRangeStart и EditRangeEnd. Совместно с вышеуказанными методами используется свойство KeyExclusive типа Boolean, которое определяет, как учитывается заданное граничное значение при анализе записей. Если оно равно true, то записи, у которых значения полей совпадают с границами, включаются в набор данных, иначе - нет. Пример включения фильтрации: with Table1 do begin IndexName:=`indProcent`; SetRangeStart; FieldByName(`Procent`).asInteger:=10; SetRangeEnd; FieldByName(`Procent`).asInteger:=30; ApplyRange; end; Отключение фильтрации: Table1.CancelRange; Метод SetRange объединяет возможности методов SetRangeStart, SetRangeEnd и ApplyRange. Процедура SetRange(const StartValues, EndValues: array of const) позволяет одновременно задать границы диапазона и выполнить фильтрацию. Пример: Table1.IndexName:=`indProcent`; Table1.SetRange([`10`],[`30`]); |
Краткий справочник по oracle
1. Введение
В справочник включены краткие сведения о языке PL/SQL, синтаксис предложений
и некоторых фраз языка SQL (подробно они будут описаны в другом документе),
краткие описания конструкций, включаемых в эти языки, а также информация о
2. Имена объектов базы данных
Имена объектов базы данных (таблиц, представлений, последовательностей,
"снимков", пакетов, процедур и функций) должны содержать не более 30 символов
и начинаться с буквы. После начальной буквы имя может любые содержать буквы,
цифры и символы "$", "#", и "_", однако полученное сочетание (имя) не может
быть зарезервированным словом Oracle (см. п. 3). Если же возникает необходимость
использовать в имени любые символы кроме кавычек и (или) составлять его из
нескольких слов, то такое имя надо заключить в кавычки (например, "Это имя
столбца".
Имя базы данных не должно превышать 8 символов.
3. Зарезервированные слова Oracle7 и PL/SQL
SQL резервные слова (слова отмеченные * используются также в PL/SQL):
ACCESS* DEFAULT* INTEGER OPTION* START*
ADD* DELETE* INTERSECT* OR* SUCCESSFUL
ALL* DESC* INTO* ORDER* SYNONYM
ALTER* DISTINCT* IS* PCTFREE* SYSDATE
AND* DROP* LEVEL* PRIOR* TABLE*
ANY* ELSE* LIKE* PRIVILEGES THEN*
AS* EXCLUSIVE LOCK PUBLIC* TO*
ASC* EXISTS* LONG RAW TRIGGER
AUDIT FILE MAXEXTENTS RENAME* UID
BETWEEN* FLOAT MINUS* RESOURCE* UNION*
BY* FOR* MODE REVOKE UNIQUE*
CHAR* FROM* MODIFY ROW UPDATE*
CHECK* GRANT* NOAUDIT ROWID USER
CLUSTER* GROUP* NOCOMPRESS* ROWLABEL VALIDATE
COLUMN HAVING* NOT* ROWNUM* VALUES*
COMMENT IDENTIFIED* NOWAIT ROWS VARCHAR*
COMPRESS* IMMEDIATE NULL* SELECT* VARCHAR2*
CONNECT* IN* NUMBER* SESSION VIEW*
CREATE* INCREMENT OF* SET* WHENEVER
CURRENT* INDEX* OFFLINE SHARE WHERE*
DATE* INITIAL ON* SIZE* WITH*
DECIMAL INSERT ONLINE SMALLINT
- 5 -
PL/SQL резервные слова
ABORT CREATE GOTO PACKAGE SUM
ACCEPT CURRENT GRANT PARTITION TABAUTH
ACCESS CURSOR GROUP PCTFREE TABLE
ADD DATABASE HAVING PRAGMA TABLES
ALL DATA_BASE IDENTIFIED PRIOR TASK
ALTER DATE IF PRIVATE TERMINATE
AND DBA IN PROCEDURE THEN
ANY DEBUGOFF INDEX PUBLIC TO
ARRAY DEBUGON INDEXES RAISE TRUE
AS DECLARE INDICATOR RANGE TYPE
ASC DEFAULT INSERT RECORD UNION
ASSERT DEFINITION INTERSECT RELEASE UNIQUE
ASSIGN DELAY INTO REM UPDATE
AT DELETE IS RENAME USE
AUTHORIZA DELTA LEVEL RESOURCE VALUES
TION DESC LIKE RETURN VARCHAR
AVG DIGITS LIMITED REVERSE VARCHAR2
BEGIN DISPOSE LOOP REVOKE VARIANCE
BETWEEN DISTINCT MAX ROLLBACK VIEW
BODY DO MIN ROWNUM VIEWS
BOOLEAN DROP MINUS ROWTYPE WHEN
BY ELSE MOD RUN WHERE
CASE ELSIF NEW SAVEPOINT WHILE
CHAR END NOCOMPRESS WSCHEMA WITH
CHAR_BASE ENTRY NOT SELECT WORK
CHECK EXCEPTION NULL SEPARATE XOR
CLOSE EXCEP NUMBER SET
CLUSTER TION_INIT NUMBER_BASE SIZE
CLUSTERS EXISTS OR SPACE
COLAUTH EXIT ON SQL
COLUMNS FALSE OPEN SQLCODE
COMMIT FETCH OPTION SQLERRM
COMPRESS FOR OR START
CONNECT FORM ORDER STATEMENT
CONSTANT FROM OTHERS STDDEV
COUNT FUNCTION OUT SUBTYPE
CRASH GENERIC
4. Литералы, операторы и выражения
4.1. Условные обозначения
[ ] - в эти скобки заключаются необязательные синтаксические единицы
{ } - конструкция, заключенная в эти скобки, должна рассматриваться как
одна синтаксическая единица
| - используется для разделения альтернативных синтаксических единиц
... - указывает на то, что непосредственно предшествующая синтаксическая
единица может повторяться один или несколько раз
text - `[символ | ``]...`
integer - цифра[цифра]...
number - [+|-]{цифра[цифра]...[.][цифра]...
|.цифра[цифра]...}[{e|E}[+|-]цифра[цифра]...]
expr - любое выражение
Expr_list - (expr [, expr] ...)
- 6 -
4.2. Иерархия операторов
Оператор Описание
----------- ------------------------------------------------
() Подавляет обычные правила старшинства операций.
** NOT Возведение в степень и логическое отрицание.
+ - Знак, предшествующий числовому выражению.
* / Умножение и деление.
+ - Сложение и вычитание.
|| Сочленение текстовых выражений и (или) констант.
:= Присвоение значения переменной пользователя.
=, <>, <,
>, <=, >=, Операторы сравнения,
IS NULL, используемые при
LIKE, IN, построении условий
BETWEEN
AND Логическое "И"
OR Логическое "ИЛИ"
4.3. Синтаксис выражений (expr)
1-я форма: { [[schema.]{table | view | snapshot }.]
{column | pseudo-column | ROWLABEL}
| `text` | number | sequence.{CURRVAL | NEXTVAL} | NULL }
2-я форма: function_name [( [DISTINCT | ALL] expr [, expr] ... )]
3-я форма: { (expr) | +expr | -expr | PRIOR expr | expr * expr | expr / expr
| expr + expr | expr - expr | expr || expr }
Decode_expr: DECODE( expr, search, result [, search, result] ... [, default] )
Если значение expr = search, то возвращает значение result, иначе
значение default или NULL (при отсутствии default).
4.4. Синтаксис условий (condition)
1-я форма: { expr {= | <> | > | < | >= | <=}
{expr | (subquery)} | expr_list {= | <>} (subquery) }
2-я форма: { expr {= | <> | > | < | >= | <=}
{ANY | SOME | ALL} {expr_list | (subquery)} | expr_list {= | <>}
{ANY | SOME | ALL} ( { expr_list [, expr_list] ... | subquery} ) }
3-я форма: { expr [NOT] IN {expr_list | (subquery)}
| expr_list [NOT] IN ( { expr_list [, expr_list]... | subquery} ) }
4-я форма: expr [NOT] BETWEEN expr AND expr
5-я форма: expr IS [NOT] NULL
6-я форма: EXISTS (subquery)
7-я форма: char1 [NOT] LIKE char2 [ESCAPE `c`]
8-я форма: { ( условие )
| NOT условие
| условие AND условие
| условие OR условие }
- 7 -
4.5. Логические операторы
NOT Реверсирование результата логического выражения (условия).
NOT | true false null
------|-------------------
| false true null
AND Логическая операция "И" соединяющая два или несколько условий
(логических выражений). В зависимости от истинности (true) или
ложности (false) этих условий результат определяется по правилам:
AND | true false null
------|--------------------
true | true false null
false | false false false
null | null false null
OR Логическая операция "ИЛИ" соединяющая два или несколько условий
(логических выражений). В зависимости от истинности (true) или
ложности (false) этих условий результат определяется по правилам:
OR | true false null
------|-------------------
true | true true true
false | true false null
null | true null null
4.6. Операторы, используемые в предложении SELECT
UNION Объединение двух запросов; результат состоит из неповторяющиеся строк,
выданных каждым из объединяемых запросов.
UNION ALL Объединение двух запросов; результат состоит из всех строк, выданных
каждым из объединяемых запросов.
INTERSECT Комбинация двух запросов; результат состоит из строк, которые выданы
как первым, так и вторым запросом.
MINUS Комбинация двух запросов; результат состоит из строк, которые выданы
первым запросом, но не выданы вторым запросом.
(+) Оператор внешнего соединения.
* Заменяет список имен всех столбцов таблицы или представления.
PRIOR Используется в древовидных структурах для указания направления
просмотра: от корня до листьев или от листьев до корня.
ALL Сохраняет дубликаты строк в результате запроса (ALL устанавливается
по умолчанию).
DISTINCT Исключает дубликаты строк из результата запроса.
5. Типы данных ORACLE7
Тип данных Описание
---------------- -------------------------------------------------------------
CHAR(размер) Используется для хранения текстовых строк фиксированной длины.
По умолчанию размер 1, максимальный размер 255.
DATE Используется для хранения информации о дате и времени (дата,
час, минута и секунда). Интервал дат: 1 января 4712 до н.э.
- 31 декабря 4712 н.э.
LONG Используется для хранения больших строк переменной длины (до
2 гигабайт).
LONG RAW Используется для хранения двоичных строк (до 2 гигабайт).
- 8 -
Тип данных Описание
---------------- -------------------------------------------------------------
NUMBER(точность, Служат для хранения чисел всех типов (целые, с плавающей
масштаб) точкой и т.д.). Точность изменяется от 0 до 38 (по умолчанию
38), а масштаб от -84 до 127 (по умолчанию 0). Если задается
отрицательный масштаб, то Oracle7 округляет значение слева от
десятичной точки.
RAW(размер) Применяется для хранения небольших двоичных строк (меньше
2000 байт).
ROWID Используется для хранения шестнадцатиричных значений ROWID.
VARCHAR2(размер) Используется для хранения строк переменной длины. По
умолчанию размер 1, максимальный размер 2000.
Преобразование данных с помощью функций SQL и ORACLE7
To |
From | CHAR DATE NUMBER RAW ROWID
-------|-----------------------------------------------------------
CHAR | TO_DATE TO_NUMBER HEXTORAW CHARTOROWID
DATE | TO_CHAR
NUMBER | TO_CHAR TO_DATE
RAW | RAWTOHEX
ROWID | ROWIDTOCHAR
Допустимые преобразования
To |
From | CHAR DATE LONG NUMBER RAW ROWID VARCHAR2
---------|-----------------------------------------------------
CHAR | yes yes yes yes yes yes
DATE | yes yes yes
LONG | yes yes yes
NUMBER | yes yes yes
RAW | yes yes yes
ROWID | yes yes
VARCHAR2 | yes yes yes yes yes yes
6. Комментарии
Для включения комментариев в предложения SQL и командные блоки PL/SQL можно
либо расположить текст комментария между парами символов /* и */ (например,
UPDATE Блюда /* Это имя модифицируемой таблицы */ SET ...), либо предварить его
двумя дефисами (например, DELETE FROM Блюда -- Удаление строк таблицы Блюда).
С помощью первого способа можно включать многострочные комментарии. Для
включения многострочных комментариев вторым способом приходится помещать "--"
перед каждой их строкой. Следует заметить, что комментарии, отмеченные "--"
могут располагаться либо в отдельных строках, либо в конце строк текста
комментируемого предложения (строк текста блока PL/SQL).