ГЛАВА 2


ОСНОВЫ

В живописи шесть главных вещей. Первая - это дух; вторая - ритм; третья - мысль; четвертая - пейзаж; пятая - кисть; и последняя - тушь. Цзинь Хао

Предыдущая глава представила общие сведения о языке PL/SQL. Эта глава фокусируется на мелких аспектах языка. Как и любой другой язык программирования, PL/SQL имеет свое кодовое множество, зарезервированные слова, пунктуацию, типы данных, жесткий синтаксис, а также фиксированые правила формирования и использования предложений. С помощью этих базовых элементов PL/SQL вы представляете объекты и операции реального мира.

Кодовое множество

Вы пишете программу PL/SQL как строки текста, используя специфический набор символов. В этот набор символов входят:

PL/SQL не различает прописных и строчных букв, и рассматривает строчные буквы как эквиваленты соответствующих прописных букв, исключая строковые и символьные литералы.

Лексические единицы

Строка текста программы PL/SQL распадается на группы символов, называемые ЛЕКСИЧЕСКИМИ ЕДИНИЦАМИ, которые можно классифицировать следующим образом:

Например, строка
        bonus := salary * 0.10;  -- вычислить премию
содержит следующие лексические единицы: Для улучшения читабельности вы можете разделять лексические единицы пропусками. На самом деле, вы обязаны разделять соседние идентификаторы пропусками или знаками пунктуации. Например, следующая строка незаконна, потому что зарезервированные слова END и IF соединены:
        IF x > y THEN high := x; ENDIF;  -- незаконно
Однако вы не можете вставлять пропуски внутри лексических единиц, за исключением строковых литералов и комментариев. Например, следующая строка незаконна, потому что составной символ для операции присваивания (:=) разъединен:
        count : = count + 1;  -- незаконно
Чтобы показать структуру, вы можете разбивать строки с помощью возврата каретки и делать отступы с помощью пробелов или табуляций. Сравните следующие предложения IF:
        IF x>y THEN max:=x;ELSE max:=y;END IF;          IF x > y THEN
                                                            max := x;
                                                        ELSE
                                                            max := y;
                                                        END IF;

Разделители

РАЗДЕЛИТЕЛЬ - это простой или составной символ, имеющий в PL/SQL специальный смысл. Например, вы используете разделители для представления арифметических операций, таких как сложение и вычитание.

Простые символы

Простые символы кодируются как одиночные символы:

+
оператор сложения
-
оператор вычитания/отрицания
*
оператор умножения
/
оператор деления
=
оператор сравнения
<
оператор сравнения
>
оператор сравнения
(
ограничитель выражения или списка
)
ограничитель выражения или списка
;
терминатор предложения
%
индикатор атрибута
,
разделитель элементов
.
селектор компоненты
@
индикатор удаленного доступа
'
ограничитель символьной строки
"
ограничитель идентификатора
:
индикатор хост-переменной
Составные символы кодируются как пары символов:
**
оператор возведения в степень
<>
оператор сравнения
!=
оператор сравнения
~=
оператор сравнения
^=
оператор сравнения
<=
оператор сравнения
>=
оператор сравнения
:=
оператор присваивания
=>
оператор ассоциации
..
оператор интервала
||
оператор конкатенации
<<
ограничитель метки
>>
ограничитель метки
--
индикатор однострочного комментария
/*
(начальный) ограничитель многострочного комментария
*/
(конечный) ограничитель многострочного комментария

Идентификаторы

Вы используете идентификаторы для именования программных объектов и единиц PL/SQL, к которым относятся константы, переменные, исключения, курсоры, подпрограммы и пакеты. Некоторые примеры идентификаторов:

        X
        t2
        phone#
        credit_limit
        LastName
        oracle$number
Идентификатор состоит из буквы, за которой (необязательно) следуют одна или несколько букв, цифр, знаков доллара, подчеркиваний или знаков номера (#). Другие символы, такие как дефис, наклонная черта или пропуск, в идентификаторе незаконны, как показывают следующие примеры:
        mine&yours      -- незаконный амперсенд
        debit-amount    -- незаконный дефис
        on/off          -- незаконная косая черта
        user id         -- незаконный пробел
Следующие примеры показывают, что использование в идентификаторах знаков доллара, подчеркиваний и знаков номера законно:
        money$$$tree    -- законно
        SN##            -- законно
        try_again_      -- законно
Буквы в идентификаторах могут быть как прописными, так и строчными. PL/SQL не различает их, за исключением строковых и символьных литералов. Поэтому, если единственным различием между идентификаторами является регистр соответствующих букв, то PL/SQL трактует такие идентификаторы как одинаковые, как показывает следующий пример:
        lastname
        LastName        -- то же, что lastname
        LASTNAME        -- то же, что lastname и LastName
Длина идентификатора не может превышать 30 символов. Однако значащим считается каждый символ в идентификаторе, включая знаки доллара, подчеркивания и знаки номера. Например, следующие два идентификатора считаются в PL/SQL различными:
        lastname
        last_name
Идентификаторы должны быть информативными. Поэтому старайтесь использовать осмысленные имена, такие как credit_limit или cost_per_thousand. Избегайте невразумительных имен, подобных cr_lim или cpm.

Зарезервированные слова

Некоторые идентификаторы, называемые ЗАРЕЗЕРВИРОВАННЫМИ СЛОВАМИ, имеют специальный смысл в PL/SQL и не могут быть переопределены. Например, слова BEGIN и END, которые окружают исполнительную часть блока или подпрограммы, зарезервированы. Как показывает следующий пример, если вы попытаетесь переопределить зарезервированное слово, вы получите ошибку компиляции:

        DECLARE
            end  BOOLEAN;  -- незаконно; вызовет ошибку компиляции
            ...
Однако заререзированные слова можно включать как составные части в идентификаторы, как показывает следующий пример:
        DECLARE
            end_of_game  BOOLEAN;  -- законно
            ...
Как правило, зарезервированные слова пишутся прописными буквами, чтобы облегчить читабельность. Однако это необязательно; как и любые другие идентификаторы PL/SQL, зарезервированные слова можно кодировать строчными или смешанными буквами. Полный список зарезервированных слов приведен в приложении E.

Предопределенные идентификаторы

Идентификаторы, глобально объявленные в пакете STANRARD, как, например, исключение INVALID_NUMBER, можно переобъявлять. Однако такое переобъявление может приводить к ошибкам, потому что глобальное объявление перекрывается вашим локальным объявлением.

Идентификаторы в кавычках

Для большей гибкости, PL/SQL позволяет вам заключать идентификаторы в двойные кавычки. Идентификаторы в кавычках необходимы нечасто, но иногда они могут быть полезными. Такой идентификатор может содержать любую последовательность печатных символов, включая пробелы, но исключая двойные кавычки. Следовательно, следующие идентификаторы законны:

        "X+Y"
        "last name"
        "on/off switch"
        "employee(s)"
        "*** header info ***"
Максимальная длина идентификатора в кавычках составляет 30 символов, не считая кавычек.

Использование в качестве идентификаторов в кавычках зарезервированных слов PL/SQL допускается, но НЕ рекомендуется. Использование зарезервированных слов является плохой практикой программирования. Однако, некоторые из зарезервированных слов PL/SQL не являются зарезервированными в SQL. Например, зарезервированное (в PL/SQL) слово TYPE допустимо использовать в предложении SQL CREATE TABLE в качестве имени столбца. Однако, если вы обратитесь к такому столбцу в предложении SQL, содержащемся в программе PL/SQL, вы получите ошибку, как показывает следующий пример:

        SELECT acct, type, bal INTO ...  -- вызовет ошибку компиляции
Чтобы предотвратить ошибку компиляции, запишите имя столбца прописными буквами и заключите его в кавычки:
        SELECT acct, "TYPE", bal INTO ...
Нельзя записывать такое имя столбца строчными буквами (если только оно не было так закодировано в предложении CREATE TABLE). Например, следующее предложение незаконно:
        SELECT acct, "type", bal INTO ...  -- вызовет ошибку компиляции
Альтернативно, вы можете создать обзор, который переименовывает сомнительный столбец, а затем использовать этот обзор в предложениях SQL вместо базовой таблицы.

Литералы

ЛИТЕРАЛ - это явное число, символ, строка или булевское значение, не представленное идентификатором. Примерами могут служить числовой литерал 147 и булевский литерал FALSE.

Числовые литералы

В арифметических выражениях могут использоваться два вида числовых литералов: целочисленные и вещественные. Целочисленный литерал - это целое число с необязательным знаком и без десятичной точки. Примеры целочисленных литералов:

        030     6       -14     0       +32767
Вещественный литерал - это целое или дробное число с необязательным знаком и с десятичной точкой. Примеры вещественных литералов:
        6.6667   0.0    -12.0   3.14159    +8300.00     .5      25.
PL/SQL рассматривает числа, подобные 12.0 и 25., как вещественные, несмотря на то, что их значения по сути целочисленны.

Числовые литералы не могут содержать знаков доллара или запятых, но могут записываться в научной нотации. В этой нотации за числом следует символ E (или e) и необязательное целое со знаком. Например:

        2E5   1.0E-7   3.14159e0   -1E38   -9.5e-3
Буква E означает "умножить на десять в степени". Как показывает следующий пример, число, следующее за E, задает степень десяти, на которую должно быть умножено число, записанное перед E:
                    3
        5E3 = 5 x 10  = 5 x 1000 = 5000
Следовательно, число за буквой E показывает также, на сколько мест следует передвинуть десятичную точку. В последнем примере неявная десятичная точка сдвигалась на три позиции вправо; в следующем примере она сдвигается на три позиции влево:
                     -3
        5E-3 = 5 x 10  = 5 x 0.001 = 0.005

Символьные литералы

Символьный литерал - это одиночный символ, окруженный одиночными апострофами. Примеры:

        'Z'   '%'   '7'   ' '   'z'   '('
Символьные литералы включают все печатные символы в наборе символов PL/SQL: буквы, цифры, пропуски и специальные символы. PL/SQL чувствителен к регистру букв в символьных литералах. Так, литералы 'Z' и 'z' считаются различными.

Не путайте символьные литералы '0' .. '9' с числовыми литералами. Символьные литералы нельзя использовать в арифметических выражениях.

Строковые литералы

Символьное значение может быть представлено идентификатором или явно записано в виде строкового литерала, который должен быть последовательностью из нуля или более символов, заключенной в апострофы. Ниже приведены примеры строковых литералов:

        'Hello, world!'
        'XYZ Corporation'
        '10-NOV-91'
        'He said "Life is like licking honey from a thorn."'
        '$1,000,000'
Все строковые литералы, за исключением пустой строки (''), имеют тип CHAR.

Если необходимо включить апостроф в литерал, его необходимо изображать в виде двойного апострофа (''), что не то же самое, что двойная кавычка ("):

        'Don''t leave without saving your work."
PL/SQL чувствителен к регистру букв в строковых литералах. Например, следующие литералы считаются различными:
        'baker'
        'Baker'

Булевские литералы

Булевские литералы - это предопределенные значения TRUE и FALSE, а также "не-значение" NULL, которое обозначает отсутствие, неизвестность или неприменимость значения. Не забывайте, что булевские литералы НЕ являются строками.

Комментарии

Компилятор PL/SQL игнорирует комментарии, но вы не должны следовать его примеру. Добавление комментариев в вашу программу способствует ее читабельности и облегчает ее понимание. Обычно комментарии используются для описания назначения и использования каждого сегмента кода. PL/SQL поддерживает два стиля комментариев: однострочные и многострочные.

Однострочные комментарии

Однострочный комментарий начинается с двойного дефиса (--) и заканчивается концом строки. Примеры:

        -- начало обработки
        SELECT sal INTO salary FROM emp  -- взять текущий оклад
            WHERE empno = emp_id;
        bonus := salary * 0.15;  -- вычислить величину премии
Заметьте, что однострочный комментарий может начинаться на одной строке с предложением (или частью предложения).

Во время тестирования или отладки программы вы можете захотеть временно удалить строку кода. Следующий пример показывает, как вы можете "закомментировать" строку:

        -- DELETE FROM emp WHERE comm IS NULL;

Многострочные комментарии

Многострочный комментарий начинается с пары символов /* и заканчивается парой символов */. Пример:

        /* вычислить 15% премию для
           сотрудников с высоким рейтингом */
        IF rating > 90 THEN
            bonus := salary * 0.15;
        END IF;
Этот стиль позволяет, например, легко "закомментировать" секцию блока, которую вы хотите временно исключить из выполняемого кода, как показывает следующий пример:
        /* OPEN c1;
           LOOP
               FETCH c1 INTO my_empno, my_ename, my_sal;
               EXIT WHEN c1%NOTFOUND;
               ...
           END LOOP;
           CLOSE c1; */

Ограничения

Нельзя вкладывать комментарии друг в друга. Кроме того, нельзя использовать однострочные комментарии в том блоке PL/SQL, который будет обрабатываться динамически программой прекомпилятора ORACLE, потому что в этом случае символы конца строки игнорируются, и, как следствие, однострочный комментарий растянется до конца блока, а не только до конца строки. Поэтому в таких случаях используйте многострочные комментарии.

Типы данных

Каждая константа и переменная имеет ТИП ДАННЫХ, который специфицирует ее формат хранения, ограничения и допустимый интервал значений. PL/SQL предусматривает разнообразие предопределенных скалярных и составных типов данных. СКАЛЯРНЫЙ тип не имеет внутренних компонент. СОСТАВНОЙ тип имеет внутренние компоненты, которыми можно манипулировать индивидуально.

Рис.2-1 показывает предопределенные типы данных, которые вы можете использовать. Еще один скалярный тип данных, MSLABEL, доступен в Trusted ORACLE, специальной защищенной версии ORACLE. Скалярные типы распадаются на семейства числовых, символьных, календарных и булевских данных.

Рис.2-1
Предопределенные типы данных

        ╡°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°≈
        ▀                                                              ▀
        ▀                     Типы данных PL/SQL                       ▀
        ▀                                                              ▀
        ▀ ╡°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°≈ ╡°°°°°°°°°°°°°°°°°°°°≈▀
        ▀ ▀          Скалярные типы            ▀ ▀   Составные типы   ▀▀
        ▀ ▀ ╡°°°°°°°°°°°°°°°°°°≈ ╡°°°°°°°°°°°≈ ▀ ▀╡°°°°°°°°≈ ╡°°°°°°°≈▀▀
        ▀ ▀ ▀ BINARY_INTEGER   ▀ ▀ CHAR      ▀ ▀ ▀▀ RECORD ▀ ▀ TABLE ▀▀▀
        ▀ ▀ ▀ DEC              ▀ ▀ CHARACTER ▀ ▀ ▀≤°°°°°°°°╠ ≤°°°°°°°╠▀▀
        ▀ ▀ ▀ DECIMAL          ▀ ▀ LONG      ▀ ▀ ▀                    ▀▀
        ▀ ▀ ▀ DOUBLE PRECISION ▀ ▀ LONG RAW  ▀ ▀ ≤°°°°°°°°°°°°°°°°°°°°╠▀
        ▀ ▀ ▀ FLOAT            ▀ ▀ RAW       ▀ ▀                       ▀
        ▀ ▀ ▀ INT              ▀ ▀ ROWID     ▀ ▀                       ▀
        ▀ ▀ ▀ INTEGER          ▀ ▀ STRING    ▀ ▀                       ▀
        ▀ ▀ ▀ NATURAL          ▀ ▀ VARCHAR   ▀ ▀                       ▀
        ▀ ▀ ▀ NUMBER           ▀ ▀ VARCHAR2  ▀ ▀                       ▀
        ▀ ▀ ▀ NUMERIC          ▀ ≤°°°°°°°°°°°╠ ▀                       ▀
        ▀ ▀ ▀ POSITIVE         ▀ ╡°°°°°°≈      ▀                       ▀
        ▀ ▀ ▀ REAL             ▀ ▀ DATE ▀      ▀                       ▀
        ▀ ▀ ▀ SMALLINT         ▀ ≤°°°°°°╠      ▀                       ▀
        ▀ ▀ ≤°°°°°°°°°°°°°°°°°°╠ ╡°°°°°°°°°≈   ▀                       ▀
        ▀ ▀                      ▀ BOOLEAN ▀   ▀                       ▀
        ▀ ▀                      ≤°°°°°°°°°╠   ▀                       ▀
        ▀ ≤°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°╠                       ▀
        ≤°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°╠
В этом разделе описываются скалярные типы; составные типы данных обсуждаются в этой главе позже.

BINARY_INTEGER

Вы используете тип данных BINARY_INTEGER для хранения целых чисел со знаком. Интервал допустимых значений для этого типа - от -2**31 -1 до 2**31 -1 (-2147483647 .. 2147483647). PL/SQL представляет значения BINARY_INTEGER как знаковые двоичные числа, которые, в отличие от значений типа NUMBER, могут использоваться в вычислениях без преобразования. Поэтому применение переменных BINARY_INTEGER может резко увеличить производительность.

Подтипы BINARY_INTEGER

ПОДТИП ассоциирует базовый тип с ограничением, и потому определяет подмножество значений базового типа. Для удобства PL/SQL имеет следующие предопределенные подтипы типа BINARY_INTEGER:

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

NUMBER

Вы используете тип данных NUMBER для хранения чисел с фиксированой или плавающей точкой практически любого размера. Вы можете специфицировать ТОЧНОСТЬ, т.е. общее число цифр, и МАСШТАБ, который определяет место округления. Синтаксис имеет следующий вид:

        NUMBER[(точность, масштаб)]
Для спецификации точности и масштаба нельзя использовать константы или переменные; вы должны использовать целочисленные литералы.

Максимальная точность значения NUMBER равна 38; диапазон допустимых значений - от 1.0E-129 до 9.99E125. Если вы не специфицируете точность, она принимает по умолчанию максимальное значение, поддерживаемое вашей системой.

Масштаб может варьироваться от -84 до 127. Например, масштаб 2 вызывает округление до ближайшей сотой (3.456 округляется до 3.46). Масштаб может быть отрицательным, что вызывает округление слева от десятичной точки. Например, масштаб -3 вызывает округление до ближайшей тысячи (3456 округляется до 3000). Нулевой масштаб вызывает округление до ближайшего целого. Если вы не специфицируете масштаб, он по умолчанию считается равным 0.

Подтипы NUMBER

Подтипы NUMBER, приведенные ниже, имеют тот же диапазон допустимых значений, что и их базовый тип. Например, FLOAT - это просто другое имя для NUMBER.

Вы можете использовать эти подтипы для совместимости с типами данных ANSI/ISO, IBM SQL/DS и IBM DB2, или если предпочитаете более описательный идентификатор, нежели NUMBER.

CHAR

Вы используете тип данных CHAR для хранения символьных данных фиксированной длины. Внутреннее представление данных зависит от набора символов базы данных, которым может быть, например, 7-битовый код ASCII или кодовая страница 500 кода EBCDIC.

Тип данных CHAR принимает необязательный параметр, который позволяет вам специфицировать максимальную длину (вплоть до 32767 байт). Синтаксис имеет следующий вид:

        CHAR[(максимальная_длина)]
Для спецификации максимальной длины нельзя использовать константу или переменную; вы должны использовать целочисленный литерал. Если вы не специфицируете максимальную длину, она по умолчанию считается равной 1.

Не забывайте, что вы специфицируете максимальную длину переменной CHAR(n) в байтах, а не в символах. Поэтому, если переменная CHAR(n) хранит мультибайтовые символы, ее максимальная длина меньше, чем n символов.

Хотя максимальная длина переменной CHAR(n) составляет 32767 байт, максимальная ширина столбца базы данных типа CHAR равна 255 байт. Поэтому вы не можете вставлять в столбец CHAR значения длиннее 255 байт. Вы можете вставлять значения CHAR(n) в столбец базы данных LONG, ибо максимальная ширина столбца LONG составляет 2147483647 (2**31 - 1) байт, или два гигабайта. Однако вы не можете выбирать значение длиннее 32767 байт из столбца LONG в переменную CHAR(n).

Подтипы CHAR

Подтипы CHAR, приведенные ниже, имеют тот же диапазон допустимых значений, что и их базовый тип. Например, STRING - это просто другое имя для CHAR.

Вы можете использовать эти подтипы для совместимости с типами данных ANSI/ISO, IBM SQL/DS и IBM DB2, или если предпочитаете более описательный идентификатор, нежели CHAR.

VARCHAR2

Вы используете тип данных VARCHAR2 для хранения символьных данных переменной длины. Внутреннее представление данных зависит от набора символов базы данных.

Тип данных VARCHAR2 принимает обязательный параметр, который позволяет вам специфицировать максимальную длину (вплоть до 32767 байт). Синтаксис имеет следующий вид:

        VARCHAR2(максимальная_длина)
Для спецификации максимальной длины нельзя использовать константу или переменную; вы должны использовать целочисленный литерал.

Не забывайте, что вы специфицируете максимальную длину переменной VARCHAR2(n) в байтах, а не в символах. Поэтому, если переменная VARCHAR2(n) хранит мультибайтовые символы, ее максимальная длина меньше, чем n символов.

Хотя максимальная длина переменной VARCHAR2(n) составляет 32767 байт, максимальная ширина столбца базы данных типа VARCHAR2 равна 2000 байт. Поэтому вы не можете вставлять в столбец VARCHAR2 значения длиннее 2000 байт. Вы можете вставлять значения VARCHAR2(n) в столбец базы данных LONG, ибо максимальная ширина столбца LONG составляет 2147483647 (2**31 - 1) байт, или два гигабайта. Однако вы не можете выбирать значение длиннее 32767 байт из столбца LONG в переменную VARCHAR2(n).

Важные семантические различия между базовыми типами CHAR и VARCHAR2 описаны в приложении C.

Подтип VARCHAR

Подтип VARCHAR типа данных VARCHAR2 имеет тот же диапазон допустимых значений, что и его базовый тип. Вы можете использовать этот подтип для совместимости с типами данных ANSI/ISO, IBM SQL/DS и IBM DB2. Однако тип VARCHAR должен в будущем измениться в соответствии с развивающимися стандартами SQL. Поэтому хорошей идеей является использовать VARCHAR2 вместо VARCHAR.

LONG

Вы используете тип данных LONG для хранения символьных строк переменной длины. Тип данных LONG подобен типу данных VARCHAR2, с тем отличием, что максимальная длина значения LONG составляет 32760 байт.

Вы можете вставлять любое значение LONG в столбец базы данных LONG, ибо максимальная ширина столбца LONG составляет 2147483647 байт. Однако вы не можете выбирать значение длиннее 32760 байт из столбца LONG в переменную LONG.

Столбцы LONG могут хранить текст, массивы символов, или даже небольшие документы. Вы можете обращаться к столбцам LONG в предложениях UPDATE, INSERT и большинстве предложений SELECT, но НЕ в выражениях, вызовах функций или некоторых фразах SQL, таких как WHERE, GROPU BY и CONNECT BY. Для дополнительной информации обратитесь к документу ORACLE7 Server SQL Language Reference Manual.

RAW

Вы используете тип данных RAW для хранения двоичных данных или байтовых строк. Например, в переменной RAW можно было бы хранить последовательность графических символов или оцифрованное изображение. Данные RAW напоминают символьные данные, с той разницей, что PL/SQL не интерпретирует данных RAW. Аналогично, ORACLE не выполняет никаких преобразований кодового множества, когда вы передаете данные RAW из одной системы в другую.

Тип данных RAW принимает обязательный параметр, который позволяет вам специфицировать максимальную длину (вплоть до 32767 байт). Синтаксис имеет следующий вид:

        RAW(максимальная_длина)
Для спецификации максимальной длины нельзя использовать константу или переменную; вы должны использовать целочисленный литерал.

Хотя максимальная длина переменной RAW составляет 32767 байт, максимальная ширина столбца базы данных типа RAW равна 255 байт. Поэтому вы не можете вставлять в столбец RAW значения длиннее 255 байт. Вы можете вставлять значения RAW в столбец базы данных LONG RAW, ибо максимальная ширина столбца LONG RAW составляет 2147483647 байт. Однако вы не можете выбирать значение длиннее 32767 байт из столбца LONG RAW в переменную RAW.

LONG RAW

Вы используете тип данных LONG RAW для хранения двоичных данных или байтовых строк. Тип данных LONG RAW подобен типу данных LONG, с тем отличием, что данные LONG RAW не интерпретируются PL/SQL. Максимальная длина значения LONG RAW составляет 32760 байт.

Вы можете вставлять любое значение LONG RAW в столбец базы данных LONG RAW, ибо максимальная ширина столбца LONG RAW составляет 2147483647 байт. Однако вы не можете выбирать значение длиннее 32760 байт из столбца LONG RAW в переменную LONG RAW.

BOOLEAN

Вы используете тип данных BOOLEAN для хранения предопределенных значений TRUE и FALSE, а также "не-значения" NULL. Вспомните, что NULL обозначает отсутствие, неизвестность или неприменимость значения.

Тип данных BOOLEAN не принимает параметров. Булевской переменной может быть присвоено лишь одно из трех возможных значений: TRUE, FALSE или NULL. Нельзя вставлять значения TRUE и FALSE в столбец базы данных. Более того, вы не можете выбирать или извлекать значения столбцов базы данных в переменные типа BOOLEAN.

DATE

Вы используете тип данных DATE для хранения значений дат, которые имеют фиксированную длину. Тип данных DATE не принимает параметров. Действительные значения для переменных DATE лежат в интервале от 1 января 14712 г. до н.э. до 31 декабря 314712 г. н.э.

При хранении в столбце базы данных, значения типа DATE включают время дня, исчисляемое в секундах после полуночи. Компонента даты, если она отсутствует, принимает по умолчанию значение даты на первый день текущего месяца; компонента времени, если она отсутствует, принимает по умолчанию время на полночь текущей (или умалчиваемой) даты.

ROWID

Внутренне, каждая таблица в базе данных ORACLE имеет псевдостолбец ROWID, в котором хранятся 6-байтовые двоичные значения, называемые ИДЕНТИФИКАТОРАМИ СТРОК. Идентификатор строки уникально идентифицирует строку в таблице и предоставляет самый быстрый способ доступа к конкретной строке. Вы используете тип данных ROWID для хранения идентификаторов строк в читабельном формате.

ROWID - это подтип типа CHAR. Поэтому, после выбора или извлечения идентификатора строки в переменную ROWID, вы можете использовать функцию ROWIDTOCHAR, которая преобразует двоичное значение в 18-байтовую символьную строку, возвращая ее в формате

        BBBBBBBB.RRRR.FFFF
где BBBBBBBB - номер блока в файле базы данных (блоки нумеруются с 0), RRRR - номер строки в блоке (строки нумеруются с 0), FFFF - номер файла базы данных. Все эти числа шестнадцатеричные. Например, идентификатор строки
        0000000E.000A.0007
указывает на 11-ю строку 15-го блока в 7-м файле базы данных.

Как правило, переменные ROWID сравниваются с псевдостолбцом ROWID в фразе WHERE предложения UPDATE или DELETE, чтобы идентифицировать последнюю строку, извлеченную курсором. Пример приведен в секции "Извлечения между commit'ами" раздела "Перекрытие умалчиваемых блокировок" в конце главы 4.

MLSLABEL

В Trusted ORACLE, вы используете тип данных MLSLABEL для хранения двоичных, переменной длины, меток операционной системы. Trusted ORACLE использует такие метки для управления доступом к данным. Для более подробной информации обратитесь к документу Trusted ORACLE7 Server Administrator's Guide.

Вы можете использовать тип данных MLSLABEL для определения столбца базы данных. Для ссылки на такой столбец можно использовать атрибуты %TYPE и %ROWTYPE. Однако в стандартном ORACLE такие столбцы могут содержать лишь пустые значения.

В Trusted ORACLE вы можете вставлять в столбец типа MSLABEL любую действительную метку операционной системы. Если эта метка имеет текстовый формат, Trusted ORACLE автоматически преобразует ее в двоичное значение. Текстовая метка может иметь длину до 255 байт. Однако внутренняя длина значения MSLABEL имеет длину от 2 до 5 байт.

В Trusted ORACLE вы также можете выбирать значения из столбца MSLABEL в символьную переменную. Trusted ORACLE автоматически преобразует внутреннее двоичное значение в значение типа VARCHAR2.

Преобразования типов данных

Иногда бывает необходимо преобразовать значение из одного типа данных в другой. Например, если вы хотите исследовать идентификатор строки, вы должны преобразовать его в символьную строку. PL/SQL поддерживает как явные, так и неявные (автоматические) преобразования типов данных.

Явные преобразования типов

Чтобы специфицировать явные преобразования типов, вы используете встроенные функции, которые преобразуют значения из одних типов данных в другие. Рис.2-2 показывает, какую функцию следует использовать в каждой возможной ситуации. Например, чтобы преобразовать значение CHAR в значение NUMBER, вы используете функцию TO_NUMBER.

Рис.2-2
Функции преобразования типов данных

                Куда
               ║╔╔╔╔╔╔╔╔╔╔╔╘╔╔╔╔╔╔╔╘╔╔╔╔╔╔╔╔╔╘╔╔╔╔╔╔╔╔╘╔╔╔╔╔╔╔╔╔╔╔⌠
               ▓CHAR       ▀DATE   ▀NUMBER   ▀RAW     ▀ROWID      ▓
        ║╔╔╔╔╔╔╕╔╔╔╔╔╔╔╔╔╔╔╟╔╔╔╔╔╔╔╟╔╔╔╔╔╔╔╔╔╟╔╔╔╔╔╔╔╔╟╔╔╔╔╔╔╔╔╔╔╔▒
Откуда  ▓CHAR  ▓           ▀TO_DATE▀TO_NUMBER▀HEXTORAW▀CHARTORAWID▓
        ÷°°°°°°╞°°°°°°°°°°°²°°°°°°°²°°°°°°°°°²°°°°°°°°²°°°°°°°°°°°▌
        ▓DATE  ▓TO_CHAR    ▀       ▀         ▀        ▀           ▓
        ÷°°°°°°╞°°°°°°°°°°°²°°°°°°°²°°°°°°°°°²°°°°°°°°²°°°°°°°°°°°▌
        ▓NUMBER▓TO_CHAR    ▀TO_DATE▀         ▀        ▀           ▓
        ÷°°°°°°╞°°°°°°°°°°°²°°°°°°°²°°°°°°°°°²°°°°°°°°²°°°°°°°°°°°▌
        ▓RAW   ▓RAWTOHEX   ▀       ▀         ▀        ▀           ▓
        ÷°°°°°°╞°°°°°°°°°°°²°°°°°°°²°°°°°°°°°²°°°°°°°°²°°°°°°°°°°°▌
        ▓ROWID ▓ROWIDTOCHAR▀       ▀         ▀        ▀           ▓
        ═╔╔╔╔╔╔╒╔╔╔╔╔╔╔╔╔╔╔╖╔╔╔╔╔╔╔╖╔╔╔╔╔╔╔╔╔╖╔╔╔╔╔╔╔╔╖╔╔╔╔╔╔╔╔╔╔╔■

Для дополнительной информации об этих функциях обратитесь к секции "Функции преобразования типов данных" ниже в этой главе.

Неявные преобразования типов

Когда это имеет смысл, PL/SQL преобразует тип данных значения неявно. Это позволяет вам использовать литералы, переменные и параметры одного типа там, где ожидается другой тип. В следующем примере, символьные переменные start_time и finish_time хранят строковые значения, представляющие число секунд после полуночи. Разность между этими значениями должна быть присвоена числовой переменной elapsed_time. Поэтому PL/SQL неявно преобразует значения CHAR в тип NUMBER.

        DECLARE
            start_time    CHAR(5);
            finish_time   CHAR(5);
            elapsed_time  NUMBER(5);
        BEGIN
            /* Получить системное время в секундах после полуночи. */
            SELECT TO_CHAR(SYSDATE, 'SSSSS')
                INTO start_time FROM sys.dual;
            -----------------------------------
            -- выполнить какие-нибудь действия
            -----------------------------------
            /* Снова получить системное время. */
            SELECT TO_CHAR(SYSDATE, 'SSSSS')
                INTO finish_time FROM sys.dual;
            /* Вычислить затраченное время в секундах. */
            elapsed_time := finish_time - start_time;
            INSERT INTO results VALUES (..., elapsed_time);
        END;
Перед присваиванием выбранного значения столбца переменной PL/SQL, если необходимо, преобразует это значение из типа данных исходного столбца в тип данных целевой переменной. Это происходит, например, когда вы выбираете значение столбца DATE в переменную VARCHAR2. Аналогично, перед присваиванием или сравнением значения переменной со значением столбца базы данных PL/SQL, если необходимо, преобразует значение из типа данных переменной в тип данных целевого столбца. Если PL/SQL не может определить, какое неявное преобразование необходимо, вы получите ошибку компиляции. В таких случаях вы должны использовать явные функции преобразования типов данных. На рис.2-3 показано, какие неявные преобразования типов данных может выполнять PL/SQL.
Рис.2-3
Неявные преобразования типов данных

                 Куда
                 ║╔╔╔╔╔╔╔╘╔╔╔╔╘╔╔╔╔╘╔╔╔╔╘╔╔╔╔╔╔╘╔╔╔╔╘╔╔╔╔╔╘╔╔╔╔╔╔╔╔⌠
                 ▓BINARY_▀CHAR▀DATE▀LONG▀NUMBER▀RAW ▀ROWID▀VARCHAR2▓
                 ▓INTEGER▀    ▀    ▀    ▀      ▀    ▀     ▀        ▓
        ║╔╔╔╔╔╔╔╔╕╔╔╔╔╔╔╔╟╔╔╔╔╟╔╔╔╔╟╔╔╔╔╟╔╔╔╔╔╔╟╔╔╔╔╟╔╔╔╔╔╟╔╔╔╔╔╔╔╔▒
Откуда  ▓BINARY_ ▓       ▀ Да ▀    ▀ Да ▀  Да  ▀    ▀     ▀   Да   ▓
        ▓INTEGER ▓       ▀    ▀    ▀    ▀      ▀    ▀     ▀        ▓
        ÷°°°°°°°°╞°°°°°°°²°°°°²°°°°²°°°°²°°°°°°²°°°°²°°°°°²°°°°°°°°▌
        ▓CHAR    ▓  Да   ▀    ▀ Да ▀ Да ▀  Да  ▀ Да ▀ Да  ▀   Да   ▓
        ÷°°°°°°°°╞°°°°°°°²°°°°²°°°°²°°°°²°°°°°°²°°°°²°°°°°²°°°°°°°°▌
        ▓DATE    ▓       ▀ Да ▀    ▀ Да ▀      ▀    ▀     ▀   Да   ▓
        ÷°°°°°°°°╞°°°°°°°²°°°°²°°°°²°°°°²°°°°°°²°°°°²°°°°°²°°°°°°°°▌
        ▓LONG    ▓       ▀ Да ▀    ▀    ▀      ▀ Да ▀     ▀   Да   ▓
        ÷°°°°°°°°╞°°°°°°°²°°°°²°°°°²°°°°²°°°°°°²°°°°²°°°°°²°°°°°°°°▌
        ▓NUMBER  ▓  Да   ▀ Да ▀    ▀ Да ▀      ▀    ▀     ▀   Да   ▓
        ÷°°°°°°°°╞°°°°°°°²°°°°²°°°°²°°°°²°°°°°°²°°°°²°°°°°²°°°°°°°°▌
        ▓RAW     ▓       ▀ Да ▀    ▀ Да ▀      ▀    ▀     ▀   Да   ▓
        ÷°°°°°°°°╞°°°°°°°²°°°°²°°°°²°°°°²°°°°°°²°°°°²°°°°°²°°°°°°°°▌
        ▓ROWID   ▓       ▀ Да ▀    ▀    ▀      ▀    ▀     ▀   Да   ▓
        ÷°°°°°°°°╞°°°°°°°²°°°°²°°°°²°°°°²°°°°°°²°°°°²°°°°°²°°°°°°°°▌
        ▓VARCHAR2▓  Да   ▀ Да ▀ Да ▀ Да ▀  Да  ▀ Да ▀ Да  ▀        ▓
        ═╔╔╔╔╔╔╔╔╒╔╔╔╔╔╔╔╖╔╔╔╔╖╔╔╔╔╖╔╔╔╔╖╔╔╔╔╔╔╖╔╔╔╔╖╔╔╔╔╔╖╔╔╔╔╔╔╔╔■
Вы сами должны гарантировать преобразуемость значений. Например, PL/SQL может преобразовать значение типа CHAR '02-JUN-92' в значение типа DATE, но он не может преобразовать в тип DATE символьную строку 'YESTERDAY'. Аналогично, PL/SQL не может преобразовать в тип NUMBER значение CHAR, содержащее нецифровые символы.

Сопоставление неявных и явных преобразований

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

Значения DATE

Когда вы выбираете значение столбца DATE в переменную CHAR или VARCHAR2, PL/SQL должен преобразовать внутреннее двоичное значение в символьное. Поэтому PL/SQL вызывает функцию TO_CHAR, которая возвращает символьную строку в умалчиваемом формате даты. Чтобы получить дату в другом формате, например, с временем, или юлианскую дату, вы должны использовать функцию TO_CHAR с подходящей маской формата.

Преобразование также необходимо, когда вы вставляете значение типа CHAR или VARCHAR2 в столбец DATE. В этом случае PL/SQL вызывает функцию TO_DATE, которая ожидает встретить умалчиваемый формат даты. Чтобы вставить дату в ином формате, вы должны вызывать TO_DATE с маской формата.

Значения RAW и LONG RAW

Когда вы выбираете значение столбца RAW или LONG RAW в переменную CHAR или VARCHAR2, PL/SQL должен преобразовать внутреннее двоичное значение в символьное. В этом случае PL/SQL возвращает каждый двоичный байт значения RAW или LONG RAW как пару символов, каждый из которых представляет шестнадцатеричный эквивалент полубайта. Например, PL/SQL возвращает двоичный байт 11111111 как пару символов 'FF'. Функция RAWTOHEX выполняет аналогичное преобразование.

Преобразование также необходимо, когда вы вставляете значение типа CHAR или VARCHAR2 в столбец RAW или LONG RAW. Каждая пара символов в значении переменной должна представлять шестнадцатеричный эквивалент двоичного байта. Если какой-либо из символов не представляет собой шестнадцатеричную цифру, будет возбуждено исключение.

Объявления

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

Вы можете объявлять переменные и константы в декларативной части любого блока PL/SQL, подпрограммы или пакета. Объявление распределяет место для значения, специфицирует его тип данных и задает имя, по которому можно обращаться к этому значению. Объявление может также присвоить начальное значение и специфицировать ограничение NOT NULL. Примеры:

        birthdate  DATE;
        emp_count  SMALLINT := 0;
        acct_id    VARCHAR2(5) NOT NULL := 'AP001';
Первое объявление именует переменную типа DATE. Второе объявление именует переменную типа SMALLINT и использует оператор присваивания (:=), чтобы присвоить этой переменной нулевое начальное значение. Третье объявление именует переменную типа VARCHAR2, специфицирует для нее ограничение NOT NULL и присваивает ей начальное значение 'AP001'.

Нельзя присваивать значения NULL переменным или константам, объявленным как NOT NULL. Если вы попытаетесь это сделать, будет возбуждено предопределенное исключение VALUE_ERROR. За ограничением NOT NULL должна следовать фраза инициализации; в противном случае вы получите ошибку компиляции. Например, следующее объявление незаконно:

        acct_id    VARCHAR2(5) NOT NULL;  -- нет начального значения
Как показывают следующие примеры, инициализирующее выражение может быть сколь угодно сложным и может ссылаться на ранее инициализированные переменные и константы:
        pi      CONSTANT REAL := 3.14159;
        radius  REAL := 1;
        area    REAL := pi * radius**2;
В объявлениях констант зарезервированное слово CONSTANT должно предшествовать спецификатору типа, как показывает следующий пример:
        credit_limit  CONSTANT REAL := 5000.00;
Это объявление именует константу типа REAL и присваивает ей начальное (и пожизненное) значение 5000. Константа ДОЛЖНА быть инициализирована в своем объявлении; иначе вы получите ошибку компиляции.

Использование DEFAULT

Если хотите, вы можете использовать зарезервированное слово DEFAULT вместо оператора присваивания, чтобы инициализировать переменную или константу. Например, объявления

        tax_year  SMALLINT := 92;
        valid     BOOLEAN := FALSE;
можно переписать следующим образом:
        tax_year  SMALLINT DEFAULT 92;
        valid     BOOLEAN DEFAULT FALSE;
Можно также использовать DEFAULT для инициализации параметров подпрограмм, параметров курсоров и полей в пользовательских записях.

Использование %TYPE

Атрибут %TYPE представляет тип данных переменной, константы или столбца базы данных. В следующем примере, %TYPE представляет тип данных переменной:

        credit  REAL(7,2);
        debit   credit%TYPE;
Переменные и константы, объявленные с атрибутом %TYPE, трактуются так, как если бы они были объявлены с явным типом данных. Например, в примере выше PL/SQL рассматривает переменную debit как переменную типа REAL(7,2).

Следующий пример показывает, что объявление через %TYPE может включать фразу инициализации:

        balance          NUMBER(7,2);
        minimum_balance  balance%TYPE := 10.00;
Атрибут %TYPE особенно полезен при объявлении переменных, которые ссылаются на столбцы базы данных. Вы можете ссылаться на таблицу и столбец, или указывать также и владельца таблицы, как показывает следующий пример:
        my_dname  scott.dept.dname%TYPE;
Использование атрибута %TYPE при объявлении my_dname имеет два преимущества. Во-первых, вы не обязаны знать точный тип столбца dname. Во-вторых, если определение столбца dname изменится, то тип данных переменной my_dname изменится соответственно во время выполнения.

Заметим, однако, что ограничение столбца NOT NULL НЕ применяется к переменным, объявленным через атрибут %TYPE. В следующем примере, даже если столбец базы данных empno определен как NOT NULL, вы все же можете присваивать пустое значение переменной my_empno:

        DECLARE
            my_empno  emp.empno%TYPE;
            ...
        BEGIN
            my_empno := NULL;  -- это будет работать
            ...
        END;

Использование %ROWTYPE

Атрибут %ROWTYPE возвращает тип записи, представляющей строку в таблице (или обзоре). Такая запись может содержать целую строку данных, выбранных из таблицы или извлеченных курсором. В следующем примере вы объявляете две записи. Первая из них хранит строку, выбранную из таблицы emp. Вторая запись хранит строку, извлеченную курсором c1.

        DECLARE
            emp_rec  emp%ROWTYPE;
            CURSOR c1 IS SELECT deptno, dname, loc FROM dept;
            dept_rec  c1%ROWTYPE;
            ...
Столбцы в строке таблицы и соответствующие поля в записи имеют одинаковые имена и типы данных. В следующем примере вы выбираете значения столбцов в запись с именем emp_rec:
        DECLARE
            emp_rec  emp%ROWTYPE;
            ...
        BEGIN
            SELECT * INTO emp_rec FROM emp WHERE ...
            ...
        END;
Значения столбцов, возвращаемые предложением SELECT, размещаются в индивидуальных полях записи. Вы обращаетесь к конкретному полю, используя квалифицированые ссылки. Например, вы могли бы обратиться к полю deptno следующим образом:
        IF emp_rec.deptno = 20 THEN ...
Кроме того, вы можете присваивать значение выражения PL/SQL конкретному полю, как показывают следующие примеры:
        emp_rec.ename := 'JOHNSON';
        emp_rec.sal := emp_rec.sal * 1.15;
Нельзя включать выражений инициализации в объявления тех переменных, которые используют %ROWTYPE. Тем не менее, есть два способа присвоить значения сразу всем полям записи. Во-первых, PL/SQL разрешает агрегатные присваивания между целыми записями, если их объявления ссылаются на одну и ту же таблицу или курсор. Например, следующие присваивания законны:
        DECLARE
            dept_rec1  dept%ROWTYPE;
            dept_rec2  dept%ROWTYPE;
            CURSOR c1 IS SELECT deptno, dname, loc FROM dept;
            dept_rec3  c1%ROWTYPE;
            dept_rec4  c1%ROWTYPE;
        BEGIN
            ...
            dept_rec1 := dept_rec2;
            dept_rec4 := dept_rec3;
            ...
Однако, так как запись dept_rec2 базируется на таблице, а запись dept_rec3 - на курсоре, следующее присваивание НЕЗАКОННО:
        dept_rec2 := dept_rec3;  -- незаконно
Во-вторых, вы можете присвоить записи список значений столбцов, используя предложения SELECT...INTO или FETCH...INTO, как показывает следующий пример. Имена столбцов должны появляться в том порядке, в каком они были объявлены в предложениях CREATE TABLE или CREATE VIEW при создании таблицы или обзора.
        DECLARE
            dept_rec  dept%ROWTYPE;
            ...
        BEGIN
            SELECT deptno, dname, loc INTO dept_rec FROM dept
                WHERE deptno = 30;
            ...
        END;
Однако вы не можете использовать оператор присваивания для присваивания записи списка значений. Поэтому следующее присваивание НЕЗАКОННО:
        имя_записи := (значение1, значение2, значение3);  -- незаконно
Хотя вы можете извлекать целые записи, вы не можете вставлять их. Например, следующее предложение незаконно:
        INSERT INTO dept VALUES (dept_rec1);  -- незаконно

Алиасы

Каждый элемент списка, извлекаемого из курсора, ассоциированного с атрибутом %ROWTYPE, должен именоваться простым идентификатором, или, если это выражения, должны иметь алиасы. В следующем примере вы используете алиас wages:

        -- доступен на диске в файле EXAMP4
        DECLARE
            CURSOR my_cursor IS SELECT sal + NVL(comm, 0) wages, ename
                FROM emp;
            my_rec  my_cursor%ROWTYPE;
        BEGIN
            OPEN my_cursor;
            LOOP
                FETCH my_cursor INTO my_rec;
                EXIT WHEN my_cursor%NOTFOUND;
                IF my_cursor.wages > 2000 THEN
                    INSERT INTO temp VALUES (null, my_rec.wages,
                        my_rec.ename);
                END IF;
            END LOOP;
            CLOSE my_cursor;
        END;
Для дополнительной информации об алиасах имен столбцов обратитесь к документу ORACLE7 Server SQL Language Manual.

Ограничения

PL/SQL не допускает ссылок вперед. Вы должны объявить переменную или константу ПРЕЖДЕ, чем ссылаться на нее в других предложениях, включая другие объявления. Например, следующее объявление переменной maxi незаконно:

        maxi  INTEGER := 2 * mini;
        mini  INTEGER := 15;
Однако PL/SQL допускает упреждающие объявления подпрограмм. Для дополнительной информации обратитесь к разделу "Упреждающие объявления" в главе 6.

Некоторые языки позволяют вам объявлять целый список переменных, принадлежащих одному и тому же типу данных. PL/SQL НЕ ПОЗВОЛЯЕТ этого. Например, следующее объявление незаконно:

        i, j, k  SMALLINT;  -- незаконно
Правильный вариант таков:
        i  SMALLINT;
        j  SMALLINT;
        k  SMALLINT;

Соглашения об именах

Одни и те же соглашения об именах действительны для всех программных объектов и единиц PL/SQL, включая константы, переменные, курсоры, исключения, процедуры, функции и пакеты. Имена могут быть простыми, квалифицированными, удаленными или квалифицированными удаленными. Например, вы можете обращаться к процедуре с именем raise_salary любым из следующих способов:
        raise_salary(...);                      -- простое
        emp_actions.raise_salary(...);          -- квалифицированное
        raise_salary@newyork(...);              -- удаленное
        emp_actions.raise_salary@newyork(...);  -- квалифиц. удаленное
В первом случае вы просто указываете имя процедуры. Во втором случае вы должны квалифицировать имя процедуры именем пакета, потому что процедура хранится в пакете с именем emp_actions. В третьем случае вы обращаетесь к связи баз данных newyork, потому что (независимая) процедура находится на удаленной базе данных. В четвертом случае вы квалифицируете имя процедуры именем пакета и указываете связь к базе данных.

Синонимы

Вы можете создавать синонимы, чтобы обеспечить прозрачность местоположения для объектов удаленных баз данных, таких как таблицы, последовательности, обзоры, независимые подпрограммы и пакеты. Однако нельзя создавать синонимы для объектов, объявленных внутри подпрограмм или пакетов. К таким объектам относятся константы, переменные, курсоры, исключения и пакетированные процедуры. Для дополнительной информации обратитесь к разделам "Удаленный доступ" в главе 4 и "Хранимые подпрограммы" в главе 6.

Сфера

Внутри одной сферы все объявляемые идентификаторы должны быть уникальными. Так, переменные и параметры, даже если их типы данных различаются, не могут иметь одинаковые имена. Например, два из следующих трех объявлений незаконны:

        DECLARE
            valid_id  BOOLEAN;
            valid_id  VARCHAR2(5);  -- незаконное повторение имени
            valid_id  INTEGER;      -- незаконное повторение имени
О правилах сферы, действующих для переменных и параметров, смотрите в разделе "Сфера и видимость".

Чувствительность к регистру букв

Как и прочие идентификаторы, имена переменных и параметров нечевствительны к регистру букв. Например, PL/SQL рассматривает следующие идентификаторы как одинаковые:

        zip_code  INTEGER;
        Zip_code  INTEGER;
        ZIP_CODE  INTEGER;

Имена таблиц базы данных

В тех предложениях SQL, которые потенциально двусмысленны, имена локальных переменных и формальных параметров имеют преимущество над именами таблиц базы данных. Например, следующее предложение UPDATE оказывается ошибочным из-за того, что PL/SQL полагает, что emp ссылается на счетчик цикла:

        FOR emp IN 1..5 LOOP
            ...
            UPDATE emp SET bonus = 500 WHERE ...
        END LOOP;
Аналогично, следующее предложение SELECT оказывается ошибочным из-за того, что PL/SQL полагает, что emp ссылается на формальный параметр:
        PROCEDURE calc_bonus (emp NUMBER, bonus OUT REAL) IS
            avg_sal  REAL;
            ...
        BEGIN
            SELECT AVG(sal) INTO avg_sal FROM emp WHERE ...
            ...
        END;
В таких случаях вы можете уточнять имя таблицы именем владельца, как в следующем примере:
        PROCEDURE calc_bonus (emp NUMBER, bonus OUT REAL) IS
            avg_sal  REAL;
            ...
        BEGIN
            SELECT AVG(sal) INTO avg_sal FROM scott.emp WHERE ...
            ...
        END;
Однако лучшей практикой программирования было бы переименовать такую переменную или формальный параметр.

Имена столбцов базы данных

Имена столбцов базы данных имеют преимущество над именами локальных переменных и формальных параметров. Например, следующее предложение DELETE удаляет из таблицы emp всех сотрудников, а не только KING'а, потому что ORACLE полагает, что оба слова ename в фразе WHERE ссылаются на столбец базы данных:

        DECLARE
            ename  CHAR(10) := 'KING';
        BEGIN
            DELETE FROM emp WHERE ename = ename;
            ...
        END;
В таких случаях, чтобы избежать двусмысленности, назначайте локальным переменным и формальным параметрам имена с префиксом my_, как в следующем примере:
        DECLARE
            my_ename  CHAR(10);
            ...
Альтернативно, вы можете использовать метку блока, чтобы квалифицировать локальные ссылки, например:
        <
> DECLARE ename CHAR(10) := 'KING'; BEGIN DELETE FROM emp WHERE ename = main.ename; ... END;
Следующий пример показывает, что вы можете использовать имя подпрограммы для уточнения ссылок на локальные переменные и формальные параметры:
        PROCEDURE calc_bonus (empno NUMBER, bonus OUT REAL) IS
            avg_sal  REAL;
            name     CHAR(10);
            job      CHAR(15) := 'SALESMAN';
        BEGIN
            SELECT AVG(sal) INTO avg_sal FROM emp
                WHERE job = calc_bonus.job;  -- ссылка на локальную пер.
            SELECT ename INTO name FROM emp
                WHERE empno = calc_bonus.empno;  -- ссылка на параметр
            ...
        END;

Сфера и видимость

Ссылки на идентификатор разрешаются согласно его сфере и видимости. СФЕРА идентификатора - это та область программной единицы (блока, подпрограммы или пакета), из которой вы можете ссылаться на этот идентификатор. Идентификатор называется ВИДИМЫМ в тех областях, из которых вы можете ссылаться на него, используя неквалицифированное имя.

Например, идентификаторы, объявленные в блоке PL/SQL, считаются локальными в этом блоке и глобальными для всех его подблоков. Если глобальный идентификатор переобъявляется в подблоке, то оба идентификатора остаются в сфере. В подблоке, однако, будет видимым лишь локальный идентификатор, потому что для ссылок к глобальному идентификатору вам приходится использовать квалифицированное имя.

На рис.2-4 показаны сфера и видимость переменной с именем x, которая объявляется в окружающем блоке, а затем переобъявляется в подблоке.

Рис.2-4
Сфера и видимость

                        Сфера                  :        Видимость
                        -----                  :        ---------
                                               :
                        DECLARE                :        DECLARE
                        °°°°°°°°°°°°°°°≈       :
                           x REAL;     ▀       :           x REAL;
                                       ▀       :        °°°°°°°°°°°°°°°≈
                        BEGIN          ▀       :        BEGIN          ▀
                           ...         ▀       :           ...         ▀
        Внешняя x          DECLARE     ▀       :           DECLARE     ▀
        ---------                      ▀       :        °°°°°°°°°°°°°°°╠
                              x REAL;  ▀       :              x REAL;
                           BEGIN       ▀       :           BEGIN
                              ...      ▀       :              ...
                           END;        ▀       :           END;
                                       ▀       :        °°°°°°°°°°°°°°°≈
                           ...         ▀       :           ...         ▀
                        END;           ▀       :        END;           ▀
                        °°°°°°°°°°°°°°°╠       :        °°°°°°°°°°°°°°°╠
                                               :
        .......................................:........................
                                               :
                        DECLARE                :        DECLARE
                           x REAL;             :           x REAL;
                        BEGIN                  :        BEGIN
                           ...                 :           ...
        Внутренняя x       DECLARE             :           DECLARE
        ------------       °°°°°°°°°°°°≈       :
                              x REAL;  ▀       :              x REAL;
                                       ▀       :           °°°°°°°°°°°°≈
                           BEGIN       ▀       :           BEGIN       ▀
                              ...      ▀       :              ...      ▀
                           END;        ▀       :           END;        ▀
                          °°°°°°°°°°°°°╠       :           °°°°°°°°°°°°╠
                           ...                 :           ...
                        END;                   :        END;

                                                            Основы  2-29
Хотя нельзя объявить идентификатор дважды в одном и том же блоке, можно объявить одинаковые идентификаторы в двух разных блоках. Объекты, представленные этими идентификаторами, различны, и любое изменение одного из этих объектов не затрагивает другой.

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

        DECLARE
            A  CHAR;
            B  CHAR;
        BEGIN
            -- здесь доступны идентификаторы: A (CHAR), B
            DECLARE
                A  INTEGER;
                C  REAL;
            BEGIN
                -- здесь доступны идентификаторы: A (INTEGER), B, C
            END;

            DECLARE
                D  REAL;
            BEGIN
                -- здесь доступны идентификаторы: A (CHAR), B, D
            END;
            -- здесь доступны идентификаторы: A (CHAR), B
        END;
Вспомним, что глобальные идентификаторы можно переобъявлять в подблоке, причем в этом случае локальное объявление имеет преимущество, и подблок может ссылаться на глобальный идентификатор лишь с помощью квалифицированного имени. Квалификатором может служить метка окружающего блока, как показывает следующий пример:
        <>
        DECLARE
            birthdate  DATE;
        BEGIN
            ...
            DECLARE
                birthdate  DATE;
            BEGIN
                ...
                IF birthdate = outer.birthdate THEN
                    ...
                END IF;
            END;
        END outer;
Или, как показывает следующий пример, квалификатором может быть имя окружающей подпрограммы:
        PROCEDURE check_credit (...) IS
            rating  NUMBER;
            ...
            FUNCTION valid (...) RETURN BOOLEAN IS
                rating  NUMBER;
            BEGIN
                ...
                IF check_credit.rating < 3 THEN
                    ...
            END valid;
        BEGIN
            ...
        END check_credit;

Присваивания

Переменные и константы инициализируются при каждом входе в блок или подпрограмму. По умолчанию переменные инициализируются значением NULL. Поэтому, если вы явно не инициализируете переменную, ее значение не определено, как показывает следующий пример:
        DECLARE
            count  INTEGER;
            ...
        BEGIN
            count := count + 1;  -- count будет иметь значение null
            ...
Поэтому никогда не ссылайтесь на переменную, пока не присвоите ей значение.

Для присваивания значений переменным можно использовать предложения присваивания. Например, следующее предложение присваивает переменной bonus новое значение, перекрывая ее старое значение:

        bonus := salary * 0.15;
Выражение, стоящее справа от оператора присваивания, может быть сколь угодно сложным, но его результат должен иметь такой же тип данных, что и тип переменной, или быть преобразуемым в этот тип.

Булевские значения

Булевской переменной можно присвоить лишь значения TRUE и FALSE, либо "не-значение" NULL. Например, при объявлении

        DECLARE
            done  BOOLEAN;
            ...
следующие предложения законны:
        BEGIN
            done := FALSE;
            WHILE NOT done LOOP
                ...
            END LOOP;
        END;
Операторы отношений, будучи применены к выражениям PL/SQL, возвращают булевские значения. Поэтому следующее присваивание законно:
        done := (count > 500);

Значения базы данных

Альтернативно, вы можете использовать предложения SELECT и FETCH, чтобы заставить ORACLE присвоить значение переменной. Пример:

        SELECT ename, sal + comm INTO last_name, wages FROM emp
            WHERE empno = emp_id;
Для каждого элемента в списке SELECT должна быть специфицирована соответствующая переменная в списке INTO. Кроме того, каждый элемент списка SELECT должен возвращать значение, имеющее такой же тип данных, что и тип соответствующей переменной, или преобразуемый в этот тип. Для дополнительной информации о предложениях SELECT и FETCH обратитесь к главе 9.

Выражения и сравнения

Выражения конструируются из операндов и операторов. ОПЕРАНД - это переменная, константа, литерал или вызов функции, поставляющий значение выражению. Пример простого арифметического выражения:
        -x / 2
Унарные операторы, такие как оператор отрицания (-), действуют на один операнд; бинарные операторы, такие как оператор деления (/), действуют на два операнда. В PL/SQL нет тернарных операторов.

Простейшее выражение состоит из единственной переменной, которая непосредственно поставляет свое значение. PL/SQL ВЫЧИСЛЯЕТ выражение (т.е. находит его текущее значение), комбинируя значения операндов так, как это предписано операторами. В результате всегда получается единственное значение определенного типа данных. PL/SQL определяет этот тип данных, изучая выражение и контекст, в котором оно появляется.

Старшинство операторов

Операции внутри выражения выполняются в определенном порядке, в зависимости от их старшинства (приоритета). На рис.2-5 показан умалчиваемый порядок операций от первой к последней (сверху вниз).

Рис.2-5
Порядок операций

        ╡°°°°°°°°°°°°°°°°°°°°°°°°°°°° °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°≈
        ▀         Оператор           ▀            Операция             ▀
        │°°°°°°°°°°°°°°°°°°°°°°°°°°°°²°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°▄
        ▀ **, NOT                    ▀ возведение в степень,           ▀
        ▀                            ▀ логическое отрицание            ▀
        │°°°°°°°°°°°°°°°°°°°°°°°°°°°°²°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°▄
        ▀ +, -                       ▀ тождественность, отрицание      ▀
        │°°°°°°°°°°°°°°°°°°°°°°°°°°°°²°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°▄
        ▀ *, /                       ▀ умножение, деление              ▀
        │°°°°°°°°°°°°°°°°°°°°°°°°°°°°²°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°▄
        ▀ +, -, ||                   ▀ сложение, вычитание,            ▀
        ▀                            ▀ конкатенация                    ▀
        │°°°°°°°°°°°°°°°°°°°°°°°°°°°°²°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°▄
        ▀ =, !=, <, >, <=, >=,       ▀ сравнение                       ▀
        ▀ IS NULL, LIKE, BETWEEN, IN ▀                                 ▀
        │°°°°°°°°°°°°°°°°°°°°°°°°°°°°²°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°▄
        ▀ AND                        ▀ конъюнкция                      ▀
        │°°°°°°°°°°°°°°°°°°°°°°°°°°°°²°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°▄
        ▀ OR                         ▀ включение                       ▀
        ≤°°°°°°°°°°°°°°°°°°°°°°°°°°°°≥°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°╠
Операторы с более высоким приоритетом выполняются первыми. Например, оба следующих выражения дают результат 8, потому что деление имеет более высокий приоритет, чем сложение:
        5 + 12 / 4
        12 / 4 + 5
Для операторов одного и того же приоритета не существует никакого специального порядка выполнения.

Вы можете использовать скобки, чтобы управлять порядком вычисления выражения. Например, следующее выражение дает 7, а не 11, потому что скобки перекрывают умалчиваемый порядок:

        (8 + 6) / 2
В следующем примере вычитание выполняется раньше деления, потому что наиболее глубоко вложенное подвыражение всегда вычисляется первым:
        100 + (20 / 5 + (7 - 3))
Как показывает следующий пример, вы всегда можете использовать скобки для улучшения читабельности, даже если в них нет необходимости:
        (salary * 0.05) + (commission * 0.25)
Логические операторы Логические операторы AND, OR и NOT вычисляются согласно логике трех состояний, иллюстрируемой таблицами истинности на рис.2-6. AND и OR - бинарные операторы; NOT - унарный оператор.
Рис.2-6
Таблицы истинности

                               ╝°°°°°°°°° °°°°°°°°° °°°°°°°°°≈
                        NOT    ▓  TRUE   ▀  FALSE  ▀  NULL   ▀
                     ╜╔╔╔╔╔╔╔╔╔╕╔╔╔╔╔╔╔╔╔╟╔╔╔╔╔╔╔╔╔╟╔╔╔╔╔╔╔╔╔█
                     ▀         ▓  FALSE  ▀  TRUE   ▀  NULL   ▀
                     ≤°°°°°°°°°╗°°°°°°°°°≥°°°°°°°°°≥°°°°°°°°°╠

                               ╝°°°°°°°°° °°°°°°°°° °°°°°°°°°≈
                        AND    ▓  TRUE   ▀  FALSE  ▀  NULL   ▀
                     ╜╔╔╔╔╔╔╔╔╔╕╔╔╔╔╔╔╔╔╔╟╔╔╔╔╔╔╔╔╔╟╔╔╔╔╔╔╔╔╔█
                     ▀  TRUE   ▓  TRUE   ▀  FALSE  ▀  NULL   ▀
                     │°°°°°°°°°╞°°°°°°°°°²°°°°°°°°°²°°°°°°°°°▄
                     ▀  FALSE  ▓  FALSE  ▀  FALSE  ▀  FALSE  ▀
                     │°°°°°°°°°╞°°°°°°°°°²°°°°°°°°°²°°°°°°°°°▄
                     ▀  NULL   ▓  NULL   ▀  FALSE  ▀  NULL   ▀
                     ≤°°°°°°°°°╗°°°°°°°°°≥°°°°°°°°°≥°°°°°°°°°╠

                               ╝°°°°°°°°° °°°°°°°°° °°°°°°°°°≈
                        OR     ▓  TRUE   ▀  FALSE  ▀  NULL   ▀
                     ╜╔╔╔╔╔╔╔╔╔╕╔╔╔╔╔╔╔╔╔╟╔╔╔╔╔╔╔╔╔╟╔╔╔╔╔╔╔╔╔█
                     ▀  TRUE   ▓  TRUE   ▀  TRUE   ▀  TRUE   ▀
                     │°°°°°°°°°╞°°°°°°°°°²°°°°°°°°°²°°°°°°°°°▄
                     ▀  FALSE  ▓  TRUE   ▀  FALSE  ▀  NULL   ▀
                     │°°°°°°°°°╞°°°°°°°°°²°°°°°°°°°²°°°°°°°°°▄
                     ▀  NULL   ▓  TRUE   ▀  NULL   ▀  NULL   ▀
                     ≤°°°°°°°°°╗°°°°°°°°°≥°°°°°°°°°≥°°°°°°°°°╠
Как показывают таблицы истинности, AND возвращает значение TRUE, только если оба операнда истинны. С другой стороны, OR возвращает значение TRUE, когда любой из операндов истинен. NOT возвращает противоположное значение (логическое отрицание) своего операнда. Например, NOT TRUE возвращает FALSE.

NOT NULL возвращает NULL, потому что пустые значения не определены. Отсюда следует, что, когда вы применяете оператор NOT к NULL, результат также не определен. Будьте осторожны. Пустые значения могут приводить к неожиданным результатам; см. раздел "Обработка пустых значений" ниже в этой главе.

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

        NOT valid AND done                      NOT (valid AND done)
Если булевские переменные valid и done обе имеют значение FALSE, то первое выражение возвратит FALSE, потому что NOT старше, чем AND; иными словами, первое выражение эквивалентно следующему:
        (NOT valid) AND done
Однако второе выражение возвратит TRUE.

Операторы сравнения

Операторы сравнения сравнивают одно выражение с другим. Результатом сравнения всегда является булевское значение TRUE, FALSE или NULL. Обычно вы используете операторы сравнения в фразе WHERE предложений манипулирования данными SQL, а также в предложениях условного управления.

Операторы отношений

Операторы отношений позволяют вам сравнивать сколь угодно сложные выражения. Следующая таблица показывает смысл каждого оператора:
ОператорСмысл
=равно
!=не равно
<меньше чем
>больше чем
<=меньше или равно
>=больше или равно

Оператор IS NULL

Оператор IS NULL возвращает булевское значение TRUE, если его операнд есть NULL, и FALSE в противном случае. Сравнения, в которых участвуют пустые значения (NULL), всегда дают NULL. Поэтому для проверки значения на пустоту не используйте выражений вида

        IF значение = NULL THEN ...
Вместо этого используйте предложение:
        IF значение IS NULL THEN ...
Будьте внимательны. Пустые значения могут приводить к неожиданным результатам. Смотрите раздел "Обработка пустых значений" ниже в этой главе.

Оператор LIKE

Оператор LIKE служит для сравнения символьного значения с образцом. Прописные и строчные буквы различаются. LIKE возвращает булевское значение TRUE, если символьные образцы совпадают, и FALSE в противном случае.

Образцы, сравниваемые оператором LIKE, могут включать два специальных ("поисковых") символа. Подчеркивание (_) совпадает с любым одиночным символом; процент (%) совпадает с нулем или более любых символов. Например, если значение переменной ename равно 'JOHNSON', то следующее выражение дает TRUE:

        ename LIKE 'J%SON'

Оператор BETWEEN

Оператор BETWEEN проверяет, лежит ли значение в указанном интервале. Он означает "больше или равно меньшему значению и меньше или равно большему значению". Например, следующее выражение дает FALSE:

        45 BETWEEN 38 AND 44

Оператор IN

Оператор IN проверяет на членство в множестве. Он означает "равно любому члену множества". Множество может включать пустые значения, но они игнорируются. Например, следующее выражение НЕ удалит строк, в которых столбец ename пуст:

        DELETE FROM emp WHERE ename IN (NULL, 'KING', 'FORD');
Более того, выражения вида
        значение NOT IN множество
дают FALSE, если множество содержит NULL. Например, следующее предложение не удалит никаких строк:
        DELETE FROM emp WHERE ename NOT IN (NULL, 'KING');

Оператор конкатенации

Оператор конкатенации (||) присоединяет одну строку символов к другой. Например, выражение

        'suit' || 'case'
возвратит результат
        'suitcase'
Если оба операнда имеют тип CHAR, то оператор конкатенации возвращает значение типа CHAR. В противном случае возвращается значение типа VARCHAR2.

Булевские выражения

PL/SQL позволяет вам сравнивать переменные и константы как в предложениях SQL, так и в процедурных выражениях. Такие сравнения, называемые БУЛЕВСКИМИ ВЫРАЖЕНИЯМИ, состоят из простых или сложных выражений, разделенных операторами отношений. Часто сами булевские выражения соединяются логическими операторами AND, OR или NOT. Булевское выражение всегда дает TRUE, FALSE или NULL.

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

Арифметические

Вы можете использовать операторы отношений для сравнения чисел на равенство или неравенство. Такие сравнения - количественные; это значит, что одно число больше другого, если оно представляет большее количество. Например, при присваиваниях

        number1 := 75;
        number2 := 70;
следующее выражение дает TRUE:
        number1 > number2

Символьные

Вы можете также сравнивать символьные значения на равенство или неравенство. Такие сравнения опираются на сопоставляющую последовательность, используемую набором символов базы данных. (СОПОСТАВЛЯЮЩАЯ ПОСЛЕДОВАТЕЛЬНОСТЬ - это внутренняя упорядоченность символов в наборе символов базы данных, основанная на числовых кодах, сопоставляемых каждому символу). Одно символьное значение больше второго, если оно следует за вторым в сопоставляющей последовательности. Например, при присваиваниях

        string1 := 'Kathy';
        string2 := 'Kathleen';
следующее выражение дает TRUE:
        string1 > string2
Однако при сравнении символьных значений существуют семантические различия между типами данных CHAR и VARCHAR2. Для дополнительной информации обратитесь к приложению C.

Календарные

Вы можете сравнивать значения дат. Такие сравнения - хронологические: одна дата больше другой, если она более поздняя. Например, при присваиваниях

        date1 := '01-JAN-91';
        date2 := '31-DEC-90';
следующее выражение дает TRUE:
        date1 > date2

Рекомендации

Как правило, не следует сравнивать вещественные числа на равенство или неравенство. Вещественные числа хранятся как приближенные значения. Так, например, следующее условие не должно дать TRUE:

        count := 1;
        IF count = 1.0 THEN ...
Старайтесь использовать скобки при сравнениях. Например, следующее выражение незаконно, потому что выражение 100 < tax дает булевское значение TRUE или FALSE, которое нельзя сравнивать с числом 500:
        100 < tax < 500  -- незаконно
Правильная запись такова:
        (100 < tax) AND (tax < 500)
Булевская переменная сама по себе имеет значение TRUE или FALSE. Поэтому ее сравнение с булевским значением TRUE или FALSE избыточно. Например, если переменная done имеет тип BOOLEAN, то предложение вида
        IF done = TRUE THEN ...
можно записать проще:
        IF done THEN ...

Обработка пустых значений

Чтобы избежать некоторых общих ошибок, держите в голове следующие правила:

В следующем примере, вы могли бы ожидать, что ряд предложений будет выполнен, потому что x и y не равны. Однако вспомните, что пустые значения не определены. Поэтому равны ли x и y, считается неизвестным; условие IF дает NULL, и ряд предложений обходится.
        x := 5;
        y := NULL;
        IF x != y THEN  -- это условие даст NULL, а не TRUE
            ряд_предложений;  -- не выполняется
        END IF;
В следующем примере, вы могли бы ожидать, что ряд предложений будет выполнен, потому что a и b выглядят равными. Однако, опять-таки, это считается неизвестным; условие IF дает NULL, и ряд предложений обходится.
        a := NULL;
        b := NULL;
        IF a = b THEN  -- это условие даст NULL, а не TRUE
            ряд_предложений;  -- не выполняется
        END IF;

Оператор NOT

Вспомните, что применение логического оператора NOT к значению NULL дает NULL. Таким образом, следующие два предложения не всегда эквивалентны:

        IF x > y THEN          |        IF NOT x > y THEN
            high := x;         |            high := y;
        ELSE                   |        ELSE
            high := y;         |            high := x;
        END IF;                |        END IF;
Ряд предложений в фразе ELSE выполняется тогда, когда условие IF дает FALSE или NULL. Поэтому, когда хотя бы одно из значений x или y есть NULL, первое предложение IF присвоит переменной high значение y, тогда как второе - значение x. Если оба значения x и y непусты, то оба предложения IF работают одинаково.

Строки нулевой длины

PL/SQL трактует любую строку нулевой длины как NULL. Это включает значения, возвращаемые символьными функциями и булевскими выражениями. Например, следующие предложения присваивают целевым переменным пустые значения:

        null_string := TO_VARCHAR2('');
        zip_code := SUBSTR(address, 25, 0);
        valid := (name != '');
Поэтому для проверки пустых строк используйте оператор IS NULL, как показано ниже:
        IF my_string IS NULL THEN ...

Оператор конкатенации

Оператор конкатенации игнорирует пустые операнды. Например, выражение

        'apple' || NULL || NULL || 'sauce'
даст значение 'applesauce'.

Функции

Если функции передается пустой аргумент, она возвращает NULL, за исключением следующих трех случаев.

DECODE

Функция DECODE сравнивает свой первый аргумент с одним или несколькими поисковыми выражениями, которые спарены с результирующими выражениями. Любое из поисковых и результирующих выражений может быть пустым. Если сравнение успешно, возвращается соответствующий результат. В следующем примере, если значение rating пусто, DECODE возвращает значение 1000:

        credit_limit := DECODE(rating, NULL, 1000, 'B', 2000, 'A',4000);

NVL

Если ее первый аргумент есть NULL, функция NVL возвращает значение своего второго аргумента. В следующем примере, если hire_date есть NULL, NVL возвратит значение SYSDATE; в противном случае NVL возвратит значение hire_date:

        start_date := NVL(hire_date, SYSDATE);

REPLACE

Если ее второй аргумент есть NULL, функция REPLACE возвращает значение своего первого аргумента, независимо от того, присутствует ли необязательный третий аргумент. Например, после присваивания

        new_string := REPLACE(old_string, NULL, my_string);
значения old_string и new_string будут одинаковыми.

Если ее третий аргумент есть NULL, функция REPLACE возвращает значение своего первого аргумента, из которого удалены все вхождения второго аргумента. Например, после присваиваний

        syllabified_name := 'Gold-i-locks';
        name := REPLACE(syllabified_name, '-', NULL)
значением переменной name будет
        'Goldilocks'
Если и второй, и третий аргументы пусты, функция REPLACE просто возвращает свой первый аргумент.

Встроенные функции

PL/SQL предоставляет много мощных функций, помогающих вам манипулировать данными. Вы можете использовать функции всюду, где допускаются выражения того же типа. Более того, вы можете вкладывать вызовы функций друг в друга.

Встроенные функции распадаются на следующие категории:

В предложениях SQL можно использовать все встроенные функции, за исключением функций сообщений об ошибках SQLCODE и SQLERRM. В процедурных предложениях можно использовать все встроенные функции, за исключением смешанной функции DECODE.

Групповые функции SQL AVG, MIN, MAX, COUNT, SUM, STDDEV и VARIANCE не встроены в PL/SQL. Тем не менее, вы можете использовать их в предложениях SQL (но не в процедурных предложениях PL/SQL). Для дополнительной информации о групповых функциях обратитесь к разделу "Поддержка SQL" в главе 4.

Для каждой встроенной функции приводятся ее аргументы, типы данных этих аргументов, и тип данных возвращаемого значения. Следующий пример показывает, что функция LENGTH принимает аргумент типа VARCHAR2 и возвращает значение типа NUMBER:

        function LENGTH (str VARCHAR2) return NUMBER

Функции сообщений об ошибках

Две функции, SQLCODE и SQLERRM, дают вам информацию об ошибках выполнения PL/SQL. Эти функции НЕ допускаются в предложениях SQL.

SQLCODE

        function SQLCODE return NUMBER
Возвращает номер последнего возбужденного исключения. Эта функция имеет смысл только в обработчике исключений. Вне обработчика она всегда возвращает 0.

Для внутренне определенных исключений SQLCODE возвращает номер ошибки ORACLE, которая передала управление обработчику. Этот номер будет отрицательным, исключая случай ошибки ORACLE "no data found"; в этом случае SQLCODE возвращает +100. Для пользовательских исключений, SQLCODE возвращает +1, если вы не использовали прагму EXCEPTION_INIT, чтобы ассоциировать ваше исключение с номером ошибки ORACLE; в этом случае SQLCODE возвращает этот номер ошибки. (Для дополнительной информации о прагме EXCEPTION_INIT обратитесь к соответствующему разделу в главе 5.)

SQLERRM

        function SQLERRM [(error_number NUMBER)] return CHAR
Возвращает сообщение об ошибке, ассоциированной с текущим значением SQLCODE.

Функция SQLERRM без аргумента имеет смысл только в обработчике исключений. Вне обработчика, SQLERRM без аргумента всегда возвращает сообщение "ORA-0000: normal, successful completion".

Для внутренне определенных исключений SQLERRM возвращает сообщение, ассоциированное с встретившейся ошибкой ORACLE. Это сообщение начинается с кода ошибки ORACLE.

Для пользовательских исключений, SQLERRM возвращает сообщение "User-Defined Exception", если вы не использовали прагму EXCEPTION_INIT, чтобы ассоциировать ваше исключение с номером ошибки ORACLE; в этом случае SQLERRM возвращает соответствующее сообщение об ошибке.

Вы можете передать номер ошибки error_number как аргумент функции SQLERRM; в этом случае SQLERRM возвращает сообщение, ассоциированное с этим номером ошибки.

Числовые функции

Числовые функции принимают числовые аргументы и возвращают числовые значения. Трансцендентные функции включают тригонометрические, логарифмические и экспоненциальные функции.

Обычные тригонометрические функции (SIN, COS и TAN) и гиперболические тригонометрические функции (SINH, COSH и TANH) тесно связаны. Если n - вещественное число, а i - (мнимый) квадратный корень из -1, то

        SIN(i*n) = i*SINH(n)
        COS(i*n) = COSH(n)
        TAN(i*n) = i*TANH(n)

ABS

        function ABS (n NUMBER) return NUMBER
Возвращает абсолютное значение n.

CEIL

        function CEIL (n NUMBER) return NUMBER
Возвращает наименьшее целое, большее или равное n.

COS

        function COS (a NUMBER) return NUMBER
Возвращает косинус угла a, выраженного в радианах. Радиан равен 57.29578 градусов (180/pi). Если ваш угол a выражен в градусах, возьмите просто COS(a/57.29578).

COSH

        function COSH (n NUMBER) return NUMBER
Возвращает гиперболический косинус числа n.

EXP

        function EXP (n NUMBER) return NUMBER
Возвращает число e, возведенное в степень n. Число e (приблизительно 2.71728) выражает основание натуральных логарифмов.

FLOOR

        function FLOOR (n NUMBER) return NUMBER
Возвращает наибольшее целое, меньшее или равное n.

LN

        function LN (n NUMBER) return NUMBER
Возвращает натуральный логарифм числа n, где n больше 0.

LOG

        function LOG (m NUMBER, n NUMBER) return NUMBER
Возвращает логарифм по основанию m числа n, где m больше 1, а n больше 0.

MOD

        function MOD (m NUMBER, n NUMBER) return NUMBER
Возвращает остаток от деления m на n. Если n равно 0, возвращается m.

POWER

        function POWER (m NUMBER, n NUMBER) return NUMBER
Возвращает m в степени n. База m и степень n могут быть любыми числами, но если m отрицательно, то n должно быть целым.

ROUND

        function ROUND (m NUMBER [, n NUMBER]) return NUMBER
Округляет m до n десятичных позиций. Если n опущено, то m округляется до нуля десятичных позиций (т.е. до целого). Число n может быть отрицательным, что позволяет округлять до десятков, сотен и т.п.

SIGN

        function SIGN (n NUMBER) return NUMBER;
Возвращает -1, если n меньше нуля, 0, если n равно 0, и 1, если n больше нуля.

SIN

        function SIN (a NUMBER) return NUMBER
Возвращает синус угла a, выраженного в радианах.

SINH

        function SINH (n NUMBER) return NUMBER
Возвращает гиперболический синус числа n.

SQRT

        function SQRT (n NUMBER) return NUMBER
Возвращает квадратный корень числа n, которое не может быть отрицательным.

TAN

        function TAN (a NUMBER) return NUMBER
Возвращает тангенс угла a, выраженного в радианах.

TANH

        function TANH (n NUMBER) return NUMBER
Возвращает гиперболический тангенс числа n.

TRUNC

        function TRUNC (m NUMBER [, n NUMBER]) return NUMBER
Возвращает m, усеченное до n десятичных позиций. Если n опущено, то m усекается до нуля десятичных позиций (т.е. до целого). Число n может быть отрицательным, что позволяет обнулять цифры десятков, сотен и т.п.

Символьные функции

Символьные функции принимают символьные аргументы. Некоторые символьные функции возвращают символьные значения, остальные возвращают числовые значения. Функции, возвращающие символьные значения, всегда возвращают значение типа VARCHAR2, с двумя исключениями. Функции UPPER и LOWER возвращают значение типа CHAR, если им передан аргумент типа CHAR, и значение типа VARCHAR2 в противном случае.

ASCII

        function ASCII (char VARCHAR2) return NUMBER
Возвращает код сопоставляющей последовательности, который представляет символ char в наборе символов базы данных. Функция ASCII является обратной к функции CHR.

CHR

        function CHR (num NUMBER) return VARCHAR2
Возвращает символ, который имеет код n в сопоставляющей последоватнльности набора символов базы данных. Функция CHR является обратной к функции ASCII.

CONCAT

        function CONCAT (str1 VARCHAR2, str2 VARCHAR2) return VARCHAR2
Присоединяет строку str2 к строке str1 и возвращает результат. Если один из аргументов пуст, CONCAT возвращает другой аргумент. Если оба аргумента пусты, CONCAT возвращает NULL.

INITCAP

        function INITCAP (str VARCHAR2) return VARCHAR2
Возвращает строку str, в которой первая буква каждого слова преобразована в прописную, а остальные в строчные. Слова отделяются друг от друга пропусками или не алфавитно-цифровыми символами.

INSTR

        function INSTR (str1 VARCHAR2, str2 VARCHAR2 [, pos NUMBER [, n NUMBER]]) return VARCHAR2
Возвращает позицию n-го вхождения строки str2 в строку str1, начиная поиск с позиции pos. Если значение pos отрицательно, INSTR осуществляет поиск от конца строки str1. Если не задано pos, подразумевается 1. Если не задано n, подразумевается 1. Позиция позвращается относительно первого символа строки str1, даже если поиск начинается не с позиции 1, и выражена в СИМВОЛАХ. Если поиск неудачен, возвращается 0.

INSTRB

function INSTRB (str1 VARCHAR2, str2 VARCHAR2 [, pos NUMBER [, n NUMBER]]) return VARCHAR2
Возвращает позицию n-го вхождения строки str2 в строку str1, начиная поиск с позиции pos. Если значение pos отрицательно, INSTR осуществляет поиск от конца строки str1. Если не задано pos, подразумевается 1. Если не задано n, подразумевается 1. Позиция позвращается относительно первого символа строки str1, даже если поиск начинается не с позиции 1, и выражена в БАЙТАХ. Если поиск неудачен, возвращается 0. Для однобайтовых наборов символов функция INSTRB эквивалентна функции INSTR.

LENGTH

        function LENGTH (str CHAR) return NUMBER
        function LENGTH (str VARCHAR2) return NUMBER
Возвращает число СИМВОЛОВ в строке str. Если строка str имеет тип CHAR, то в длину входят хвостовые пробелы. Если строка str пуста, LENGTH возвращает NULL.

LENGTHB

        function LENGTHB (str CHAR) return NUMBER
        function LENGTHB (str VARCHAR2) return NUMBER
Возвращает число БАЙТ в строке str. Если строка str имеет тип CHAR, то в длину входят хвостовые пробелы. Если строка str пуста, LENGTHB возвращает NULL. Для однобайтовых наборов символов функция LENGTHB эквивалентна функции LENGTH.

LOWER

        function LOWER (str CAR) return CHAR
        function LOWER (str VARCHAR2) return VARCHAR2
Возвращает строку str, в которой все буквы преобразованы в строчные.

LPAD

        function LPAD (str VARCHAR2, len NUMBER [, pad VARCHAR2]) return VARCHAR2
Возвращает строку str, дополненную слева до длины len цепочкой символов pad, повторяющейся столько раз, сколько необходимо. Если строка pad не указана, подразумевается пробел. Если строка str длиннее len символов, то LPAD возвращает первые len символов строки str.

LTRIM

        function LTRIM (str VARCHAR2, [, set VARCHAR2]) return VARCHAR2
Возвращает строку str, из которой удалены начальные символы вплоть до первого символа, не принадлежащего множеству set. Если множество set не задано, подразумевается пробел.

NLS_INITCAP

        function NLS_INITCAP (str VARCHAR2 [,nlsparms VARCHAR2]) return VARCHAR2
Возвращает строку str, в которой первая буква каждого слова преобразована в прописную, а остальные в строчные. Слова отделяются друг от друга пропусками или не алфавитно-цифровыми символами. Значение nlsparms должно иметь форму
        'NLS_SORT = '
где sort - либо название лингвистической сортировки, либо ключевое слово BINARY. Лингвистическая сортировка удовлетворяет специальным требованиям языка при преобразованиях букв. Это может привести к тому, что NLS_INITCAP возвратит строку другой длины, чем входная строка str. Если аргумент nlsparms опущен, NLS_INITCAP использует умалчиваемую сортировку для текущей сессии. Для дополнительной информации обратитесь к документу ORACLE7 Server Application Developer's Guide.

NLS_LOWER

        function NLS_LOWER (str VARCHAR2 [,nlsparms VARCHAR2]) return VARCHAR2
Возвращает строку str, в которой все буквы преобразованы в строчные. Значение nlsparms должно иметь форму
        'NLS_SORT = '
где sort - либо название лингвистической сортировки, либо ключевое слово BINARY. Лингвистическая сортировка удовлетворяет специальным требованиям языка при преобразованиях букв. Это может привести к тому, что NLS_LOWER возвратит строку другой длины, чем входная строка str. Если аргумент nlsparms опущен, NLS_LOWER использует умалчиваемую сортировку для текущей сессии. Для дополнительной информации обратитесь к документу ORACLE7 Server Application Developer's Guide.

NLS_UPPER

        function NLS_UPPER (str VARCHAR2 [,nlsparms VARCHAR2]) return VARCHAR2
Возвращает строку str, в которой все буквы преобразованы в прописные. Значение nlsparms должно иметь форму
        'NLS_SORT = '
где sort - либо название лингвистической сортировки, либо ключевое слово BINARY. Лингвистическая сортировка удовлетворяет специальным требованиям языка при преобразованиях букв. Это может привести к тому, что NLS_UPPER возвратит строку другой длины, чем входная строка str. Если аргумент nlsparms опущен, NLS_UPPER использует умалчиваемую сортировку для текущей сессии. Для дополнительной информации обратитесь к документу ORACLE7 Server Application Developer's Guide.

NLSSORT

        function NLSSORT (str VARCHAR2 [,nlsparms VARCHAR2]) return RAW
Возвращает значение строки str в лингвистической последовательности сортировки, специфицированной аргументом nlsparms. Если аргумент nlsparms опущен, NLSSORT использует умалчиваемую сортировку для текущей сессии. Значение nlsparms должно иметь форму
        'NLS_SORT = '
где sort - либо название лингвистической сортировки, либо ключевое слово BINARY. Если специфицировано BINARY, то NLSSORT возвращает строку str.

В фразе WHERE, функция NLSSORT позволяет специфицировать сравнения на базе лингвистического, а не двоичного, упорядочения. NLSSORT также позволяет вам управлять поведением фразы ORDER BY независимо от параметра NLS_SORT. Для дополнительной информации обратитесь к документу ORACLE7 Server Application Developer's Guide.

REPLACE

        function REPLACE (str1 VARCHAR2, str2 VARCHAR2 [,str3 VARCHAR2]) return VARCHAR2
Возвращает строку str1, в которой каждое вхождение подстроки str2 заменено строкой str3. Если строка str3 не задана, то все вхождения подстроки str2 удаляются из строки str1. Если не специфицированы ни поисковая подстрока, ни строка замены, то REPLACE возвращает NULL.

RPAD

        function RPAD (str VARCHAR2, len NUMBER [, pad VARCHAR2]) return VARCHAR2
Возвращает строку str, дополненную справа до длины len цепочкой символов pad, повторяющейся столько раз, сколько необходимо. Если строка pad не указана, подразумевается пробел. Если строка str длиннее, чем len символов, то RPAD возвращает первые len символов строки str.

RTRIM

        function RTRIM (str VARCHAR2, [, set VARCHAR2]) return VARCHAR2
Возвращает символьную строку str, из которой удалены конечные символы после последнего символа, не принадлежащего множеству set. Если множество set не задано, подразумевается пробел.

SOUNDEX

        function SOUNDEX (str VARCHAR2) return VARCHAR2
Возвращает строку, представляющую собой фонетический эквивалент слов строки str. Фонетическое представление слов позволяет вам сравнивать слова, которые пишутся по-разному, но произносятся похоже. Это представление определено в книге Д.Кнута "Искусство программирования", том 3.

SUBSTR

        function SUBSTR (str VARCHAR2, pos NUMBER [, len NUMBER]]) return VARCHAR2
Возвращает подстроку строки str, начинающуюся с СИМВОЛЬНОЙ позиции pos и содержащую len символов (или, если число len опущено, все символы до конца строки str). Значение pos не может быть нулевым. Если значение pos отрицательно, SUBSTR подсчитывает символы от конца строки str. Число len должно быть положительным.

SUBSTRB

        function SUBSTRB (str VARCHAR2, pos NUMBER [, len NUMBER]]) return VARCHAR2
Возвращает подстроку строки str, начинающуюся с БАЙТОВОЙ позиции pos и содержащую len символов (или, если число len опущено, все символы до конца строки str). Значение pos не может быть нулевым. Если значение pos отрицательно, SUBSTR подсчитывает байты от конца строки str. Число len должно быть положительным. Для однобайтовых наборов символов функция SUBSTRB эквивалентна функции SUBSTR.

TRANSLATE

        function TRANSLATE (str VARCHAR2, set1 VARCHAR2, set2 CHAR) return VARCHAR2
Возвращает строку str, в которой все символы из множества set1 заменены соответствующими символами из множества set2, а все прочие символы оставлены без изменений. Если set1 содержит больше символов, чем set2, то лишние символы в конце множества set1 не имеют аналогов в множестве set2. Поэтому, если такие символы встречаются в строке str, TRANSLATE удаляет их из результирующего значения.

UPPER

        function UPPER (str CHAR) return CHAR
        function UPPER (str VARCHAR2) return VARCHAR2
Возвращает строку str, в которой все буквы преобразованы в прописные.

Функции преобразования

Функции преобразования конвертируют значение из одного типа данных в другой.

CHARTOROWID

        function CHARTOROWID (str CHAR) return ROWID
        function CHARTOROWID (str VARCHAR2) return ROWID
Преобразует строку str из типа CHAR или VARCHAR2 в тип ROWID.

CONVERT

        function CONVERT (str VARCHAR2, set1 VARCHAR2 [, set2 VARCHAR2]) return VARCHAR2
Преобразует строку str из одного набора символов (set2) в другой (set1). Как set1, так и set2 могут быть столбцами базы данных или литералами, представляющими имя набора символов. Следующая таблица показывает некоторые общеупотребительные наборы символов:
Набор символов Описание
US7ASCIIАмериканский 7-битовый ASCII
WE8DECЗападноевропейский 8-битовый DEC
WE8HPЗападноевропейский 8-битовый HP Laserjet
F7DECФранцузский 7-битовый DEC
WE8EBCDIC500Западноевропейский IBM EBCDIC, кодовая страница 500
WE8PC850IBM PC, кодовая страница 850
WE8ISO8859P1Западноевропейский 8-битовый ISO 8859-1
Для полного преобразования, целевой набор символов (set1) должен содержать представления всех символов исходного набора символов (set2). В противном случае используются символы замены, которые вы можете специфицирорвать при определении набора символов.

HEXTORAW

        function HEXTORAW (str CHAR) return RAW
        function HEXTORAW (str VARCHAR2) return RAW
Преобразует шестнадцатеричную строку str из типа CHAR или VARCHAR2 в тип RAW.

RAWTOHEX

        function RAWTOHEX (bin RAW) return VARCHAR2
Преобразует двоичное значение bin из типа RAW в шестнадцатеричную строку типа VARCHAR2.

RAWIDTOCHAR

        function RAWIDTOCHAR (bin ROWID) return VARCHAR2
Преобразует двоичное значение bin из типа RAWID в шестнадцатеричную строку типа VARCHAR2.

TO_CHAR для дат

        function TO_CHAR (dte DATE [, fmt VARCHAR2 [, nlsparms] ]) return VARCHAR2
Преобразует дату dte в символьную строку типа VARCHAR2 в формате, заданном моделью формата fmt. (Допустимые модели формата приведены в описании функции TO_DATE.) Если вы опустите fmt, подразумевается умалчиваемый формат даты.

Аргумент nlsparms специфицирует язык, в котором возвращаются названия или сокращения месяцев и дней. Он имеет следующий вид:

        'NLS_DATE_LANGUAGE = <язык>'
Если вы опустите nlsparms, то TO_CHAR использует умалчиваемый язык для текущей сессии.

TO_CHAR для чисел

        function TO_CHAR (num NUMBER [, fmt VARCHAR2 [, nlsparms] ]) return VARCHAR2
Преобразует число num в символьную строку типа VARCHAR2 в формате, заданном моделью формата fmt. (Допустимые модели формата приведены в описании функции TO_NUMBER.) Если вы опустите fmt, число num преобразуется в строку символов такой длины, которой достаточно для всех значащих цифр.

Аргумент nlsparms специфицирует следующие символы, которые возвращаются элементами числового формата:

Этот аргумент имеет следующую форму:
        'NLS_NUMERIC_CHARACTERS = ''dg'',
         NLS_CURRENCY = ''текст'',
         NLS_ISO_CURRENCY = ''текст'' '
Заметьте, что внутри строки, заключенной в апострофы, каждый апостроф представляется двумя апострофами подряд. Если вы опустите nlsparms, то TO_CHAR использует умалчиваемые значения соответствующих параметров для текущей сессии.

TO_CHAR для меток

        function TO_CHAR (label MLSLABEL [, fmt VARCHAR2]) return VARCHAR2
Преобразует метку label типа MLSLABEL в символьную строку типа VARCHAR2 в формате, заданном моделью формата fmt. Если вы опустите fmt, подразумевается умалчиваемый формат меток.

Этот вариант функции TO_CHAR используется только в Trusted ORACLE. Для дополнительной информации обратитесь к документу Trusted ORACLE7 Server Administrator's Guide.

TO_DATE

        function TO_DATE (str VARCHAR2 [, fmt VARCHAR2 [, nlsparms] ]) return DATE
        function TO_DATE (num NUMBER, [, fmt VARCHAR2 [, nlsparms] ]) return DATE
Преобразует строку str или число num в значение даты в формате, заданном fmt. Допустимые модели формата приведены в следующей таблице:
Модель форматаОписание
CC,SCCвек (S префиксует даты до н.э. минусом)
YYYY,SYYYYгод (S префиксует даты до н.э. минусом)
IYYYгод в стандарте ISO
YYY,YY,Yпоследние три, две или одна цифра года
IYY,IY,Iто же для года ISO
Y,YYYгод с запятой
YEAR,SYEARгод прописью (S префиксует даты до н.э. минусом)
RRпоследние две цифры года в новом веке
BC,ADиндикатор BC или AD
B.C.,A.D.индикатор B.C. или A.D.
Qквартал (1-4)
MMмесяц (1-12)
RMримский номер месяца (I-XII)
MONTHимя месяца
MONсокращенное имя месяца
WWнеделя года (1-53)
IWWнеделя года (1-52 или 1-53) по ISO
Wнеделя месяца (1-5)
DDDдень года (1-366)
DDдень месяца (1-31)
Dдень недели (1-7)
DAYимя дня
DYсокращенное имя дня
Jюлианский день (число дней с 1 января 4712 г. до н.э.)
AM,PMиндикатор полудня
A.M.,P.M.индикатор полудня с точками
HH,HH12час дня (1-12)
HH24час суток (0-23)
MIминута (0-59)
SSсекунда (0-59)
SSSSSсекунд после полуночи (0-86399)
Если формат опущен, подразумевается, что строка str задана в умалчиваемом формате даты. Если аргумент fmt имеет значение 'J' (юлианский день), то число num должно быть целым.

Аргумент nlsparms специфицирует язык, в котором возвращаются названия или сокращения месяцев и дней. Он имеет следующий вид:

        'NLS_DATE_LANGUAGE = <язык>'
Если вы опустите nlsparms, то TO_DATE использует умалчиваемый язык для текущей сессии.

TO_LABEL

        function TO_LABEL (str CHAR [, fmt VARCHAR2]) return MLSLABEL
        function TO_LABEL (str VARCHAR2 [, fmt VARCHAR2]) return MLSLABEL
Преобразует строку str, которая содержит метку в формате, специфицированном моделью формата fmt, в значение типа MLSLABEL. Если вы опускаете fmt, то строка str должна быть в умалчиваемом формате меток.

Эта функция используется только в Trusted ORACLE. Для дополнительной информации обратитесь к документу Trusted ORACLE7 Server Administrator's Guide.

TO_MULTI_BYTE

        function TO_MULTI_BYTE (str CHAR) return CHAR
        function TO_MULTI_BYTE (str VARCHAR2) return VARCHAR2
Возвращает строку str, в которой все однобайтовые символы преобразованы в свои мультибайтовые эквиваленты. Однобайтовые символы, не имеющие мультибайтовых эквивалентов, остаются без изменений. Эта функция полезна лишь в том случае, если набор символов вашей базы данных содержит как однобайтовые, так и мультибайтовые символы.

TO_NUMBER

        function TO_NUMBER (str CHAR [, fmt VARCHAR2 [, nlsparms] ]) return NUMBER
        function TO_NUMBER (str VARCHAR2 [, fmt VARCHAR2 [, nlsparms] ]) return NUMBER
Преобразует строку str из значения типа CHAR или VARCHAR2 в значение типа NUMBER в формате, специфицированном моделью формата fmt. Модель числового формата состоит из элементов формата, приведенных на следующей таблице:
ЭлементПримерОписание
99999значащая цифра
00999ведущий нуль (вместо пробела)
$$999ведущий знак доллара
BB999ведущий пробел (вместо нуля)
MI999MIхвостовой знак минус
SS999 ведущий знак (плюс или минус)
PR999PR отрицательные значения в угловых скобках
D99D99десятичный символ
G9G99разделитель групп
CC999символ валюты в стандарте ISO
LL999местный символ валюты
,9,999запятая
.9.999точка
V999V99умножение на 10 в степени n, где n - число девяток после V
EEEE9.99EEEEнаучная нотация
RN,rnRNримское числительное в верхнем или нижнем регистре
Строка str должна представлять действительное число. Аргумент nlsparms специфицирует следующие символы, которые возвращаются элементами числового формата: Этот аргумент имеет следующую форму:
        'NLS_NUMERIC_CHARACTERS = ''dg'',
         NLS_CURRENCY = ''текст'',
         NLS_ISO_CURRENCY = ''текст'' '
Заметьте, что внутри строки, заключенной в апострофы, каждый апостроф представляется двумя апострофами подряд. Если вы опустите nlsparms, то TO_NUMBER использует умалчиваемые значения соответствующих параметров для текущей сессии.

TO_SINGLE_BYTE

        function TO_SINGLE_BYTE (str CHAR) return CHAR
        function TO_SINGLE_BYTE (str VARCHAR2) return VARCHAR2
Возвращает строку str, в которой все мультибайтовые символы преобразованы в свои однобайтовые эквиваленты. Мультибайтовые символы, не имеющие однобайтовых эквивалентов, остаются без изменений. Эта функция полезна лишь в том случае, если набор символов вашей базы данных содержит как однобайтовые, так и мультибайтовые символы.

Календарные функции

Календарные функции принимают аргументы и возвращают значения в формате DATE, за исключением функции MONTH_BETWEEN, которая возвращает числовое значение.

ADD_MONTHS

        function ADD_MONTHS (dte DATE, num NUMBER) return DATE
        function ADD_MONTHS (num NUMBER, dte DATE) return DATE
Обе формы функции имеют один и тот же эффект. К дате dte прибавляется num месяцев, и возвращается результирующая дата. Число num должно быть целым. ADD_MONTHS всегда возвращает дату, числовое значение порции дня которой совпадает с днем даты dte, с одним исключением. Если день даты dte превышает число дней в результирующем месяце, то дата, возвращаемая функцией ADD_MONTHS, будет последним днем месяца. Таким путем ADD_MONTHS компенсирует различающиеся числа дней в разных месяцах.

LAST_DAY

        function LAST_DAY (dte DATE) return DATE
Возвращает дату последнего дня месяца, содержащего дату dte.

MONTHS_BETWEEN

        function MONTHS_BETWEEN (dte1 DATE, dte2 DATE) return NUMBER
Возвращает число месяцев между датами dte1 и dte2. Если dte1 позже dte2, результат положителен. Если dte1 раньше dte2, результат отрицателен. Если даты dte1 и dte2 попадают на одинаковые (или последние) дни соответствующих месяцев, то MONTHS_BETWEEN возвращает целое число. В противном случае MONTHS_BETWEEN возвращает дробное число, которое базируется на 31-дневном месяце и учитывает разницу между компонентами времени в датах dte1 и dte2.

NEW_TIME

        function NEW_TIME (dte DATE, zon1 VARCHAR2, zon2 VARCHAR2) return DATE
При данном значении даты/времени dte в часовом поясе zon1 возвращает соответствующее значение даты/времени в часовом поясе zon2. Следующая таблица содержит допустимые значения символьных выражений zon1 и zon2:
ЗначениеОписание
ASTАтлантическое стандартное время
ADTАтлантическое дневное время
BSTБерингово стандартное время
BDTБерингово дневное время
CSTЦентральное стандартное время
CDTЦентральное дневное время
ESTВосточное стандартное время
EDTВосточное дневное время
GMTСреднее время по Гринвичу
HSTАляска-Гавайи, стандартное время
HDT Аляска-Гавайи, дневное время
MST Маунтин, стандартное время
MDT Маунтин, дневное время
NST Ньюфаундленд, стандартное время
PST Тихоокеанское стандартное время
PDT Тихоокеанское дневное время
YST Юкон, стандартное время
YDT Юкон, дневное время

NEXT_DAY

        function NEXT_DAY (dte DATE, day VARCHAR2) return DATE
Возвращает первую дату после даты dte, название дня недели которой совпадает с значением day. day должно быть правильным названием одного из семи дней недели.

ROUND

        function ROUND (dte DATE [, fmt VARCHAR2]) return DATE
Возвращает дату dte, округленную согласно модели формата fmt. Если формат опущен, подразумевается 'DD'. Следующая таблица показывает допустимые модели форматов и соответствующие им единицы округления:
Модель форматаЕдиницы округления
CC,SCC век
SYYY,YYY,YEAR,SYEAR,YYY,YY,Y год (округляется вверх на 1 июля)
Q квартал (округляется вверх на 16-е число 2-го месяца квартала)
MONTH,MON,MM месяц (округляется вверх на 16-е)
WW начало недели ГОДА
W начало недели МЕСЯЦА
DDD,DD,J день
DAY,DY,D ближайшее воскресенье
HH,HH12,HH24 час
MI минута

SYSDATE

        function SYSDATE return DATE
Возвращает текущее значение даты/времени в системе. Эта функция не принимает аргументов.

TRUNC

        function TRUNC (ted DATE [, fmt VARCHAR2]) return DATE
Возвращает значение даты dte, компонента времени которой усечена согласно модели формата fmt. (Список допустимых моделей формата приведен в описании функции ROUND.) Если формат опущен, компонента времени удаляется из даты, т.е. осуществляется усечение на ближайший день.

Смешанные функции

DECODE

        function DECODE (expr, search1, result1 [, search2, result2] ... [default] )
Значение выражения expr сравнивается с каждым из значений search. Если expr совпадает с каким-либо search, возвращается соответствующее значение result. Если ни одного совпадения не найдено, возвращается значение default (или NULL, если значение default опущено).

expr может иметь любой тип данных, но значения search должны иметь тот же тип, как у expr. Возвращаемое значение принудительно приводится к тому типу данных, как у result1. Функция DECODE допускается только в предложениях SQL.

DUMP

        function DUMP (expr DATE [, fmt BINARY_INTEGER [, pos BINARY_INTEGER [, len BINARY_INTEGER]]]) return VARCHAR2
        function DUMP (expr NUMBER [, fmt BINARY_INTEGER [, pos BINARY_INTEGER [, len BINARY_INTEGER]]]) return VARCHAR2
        function DUMP (expr VARCHAR2 [, fmt BINARY_INTEGER [, pos BINARY_INTEGER [, len BINARY_INTEGER]]]) return VARCHAR2
Возвращает внутреннее представление значения выражения expr. Аргумент fmt определяет формат возвращаемого значения (8=восьмеричный, 10=десятичный, 16=шестнадцатеричный, 17=символьный). Аргументы pos (позиция) и len (длина) специфицируют, какая часть представления должна быть возвращена. По умолчанию возвращается полное представление в десятичном виде.

GREATEST

        function GREATEST (expr1, expr2, expr3, ...)
Возвращает наибольшее значение из списка значений. Все значения expr в списке, кроме первого, приводятся к типу данных первого значения (expr1) перед выполнением сравнений. Поэтому типы данных всех значений должны быть совместимы с типом данных первого значения. Функция GREATEST сравнивает выражения, используя недополняющую семантику (см. приложение C).

GREATEST_LB

        function GREATEST_LB (label [,label] ...) return MLSLABEL
Возвращает наибольшую нижнюю границу из списка меток. Каждая метка label в списке должна иметь тип данных MLSLABEL или должна быть литералом в апострофах в умалчиваемом формате меток.

Эта функция используется только в Trusted ORACLE. Для дополнительной информации обратитесь к документу Trusted ORACLE7 Server Administrator's Guide.

LEAST

        LEAST (expr1, expr2, expr3, ...)
Возвращает наименьшее значение из списка значений. Все значения expr в списке, кроме первого, приводятся к типу данных первого значения (expr1) перед выполнением сравнений. Поэтому типы данных всех значений должны быть совместимы с типом данных первого значения. первого значения. Функция LEAST сравнивает выражения, используя недополняющую семантику (см. приложение C).

LEAST_UB

        function LEAST_UB (label [,label] ...) return MLSLABEL
Возвращает наименьшую верхнюю границу из списка меток. Каждая метка label в списке должна иметь тип данных MLSLABEL или должна быть литералом в апострофах в умалчиваемом формате меток.

Эта функция используется только в Trusted ORACLE. Для дополнительной информации обратитесь к документу Trusted ORACLE7 Server Administrator's Guide.

NVL

        function NVL (str1 CHAR, str2 CHAR) return CHAR
        function NVL (dte1 DATE, dte2 DATE) return DATE
        function NVL (bool1 BOOLEAN, bool2 BOOLEAN) return BOOLEAN
        function NVL (num1 NUMBER, num2 NUMBER) return NUMBER
        function NVL (str1 VARCHAR2, str2 VARCHAR2) return VARCHAR2
        function NVL (lbl1 MLSLABEL, lbl2 MLSLABEL) return MLSLABEL
Все формы функции принимают два аргумента одинакового типа и возвращают значение того же типа. Если первый аргумент не NULL, возвращается значение первого аргумента. Если первый аргумент есть NULL, возвращается значение второго аргумента.

UID

        function UID return NUMBER
Возвращает идентификационный номер, который ORACLE назначил текущему пользователю. Эта функция не имеет аргументов.

USER

        function USER return VARCHAR2
Возвращает имя текущего пользователя ORACLE. Эта функция не имеет аргументов.

USERENV

        function USERENV (str VARCHAR2) return VARCHAR2
Возвращает информацию о текущей сессии, полезную для составления аудиторской таблицы или для определения используемого языка и набора символов.

Символьная строка str может иметь одно из следующих значений:

'ENTRYID'
Возвращает идентификатор аудиторской записи.
'LABEL'
Возвращает метку сессии. Эта опция доступна только в Trusted ORACLE. Для дополнительной информации обратитесь к документу Trusted ORACLE7 Server Administrator's Guide.
'LANGUAGE'
Возвращает используемые язык, территорию и набор символов базы данных.
'SESSIONID'
Возвращает идентификатор аудиторской сессии.
'TERMINAL'
Возвращает идентификатор терминала в операционной системе.
Нельзя специфицировать опцию 'ENTRYID' или 'SESSIONID' в предложениях SQL, обращающихся к удаленной базе данных.

VSIZE

        function VSIZE (expr DATE) return NUMBER
        function VSIZE (expr NUMBER) return NUMBER
        function VSIZE (expr VARCHAR2) return NUMBER
Возвращает число байт во внутреннем представлении выражения expr. Если expr есть NULL, VSIZE возвращает NULL.

Таблицы PL/SQL

PL/SQL предоставляет два составных типа данных: TABLE и RECORD. Этот раздел обсуждает тип данных TABLE; в следующем разделе обсуждается тип данных RECORD.

Объекты типа TABLE называются ТАБЛИЦАМИ PL/SQL. Эти таблицы моделируют таблицы базы данных (но не являются таковыми). Таблицы PL/SQL используют первичный ключ, чтобы предоставить вам доступ к строкам по аналогии с массивом.

Как и размер таблицы базы данных, размер таблицы PL/SQL НЕ ОГРАНИЧИВАЕТСЯ. Иными словами, число строк в таблице PL/SQL может возрастать динамически. Поэтому ваша таблица PL/SQL растет по мере добавления в нее новых строк.

Таблица PL/SQL может иметь один столбец и один первичный ключ, оба непоименованные. Столбец может принадлежать любому скалярному типу, но первичный ключ должен принадлежать типу BINARY_INTEGER. В будущих версиях PL/SQL таблицы PL/SQL смогут иметь несколько поименованных столбцов и составные первичные ключи любого типа.

Объявление таблиц PL/SQL

Таблицы PL/SQL должны объявляться за два шага. Прежде всего вы объявляете (поименованный) тип TABLE, а затем объявляете таблицы PL/SQL этого типа. Вы можете объявлять типы TABLE в декларативной части любого блока, подпрограммы или пакета, используя следующий синтаксис:

        TYPE имя_типа IS TABLE OF
            { тип_столбца | переменная%TYPE | таблица.столбец%TYPE }
            [NOT NULL] INDEX BY BINARY_INTEGER;
где имя_типа - спецификатор типа, используемый в последующих объявлениях таблиц PL/SQL, а тип_столбца - любой скалярный (не составной) тип данных, такой как CHAR, DATE или NUMBER. Альтернативно, для спецификации типа столбца можно использовать атрибут %TYPE.

В следующем примере вы объявляете тип TABLE с именем EnameTabTyp:

        DECLARE
            TYPE EnameTabTyp IS TABLE OF CHAR(10)
                INDEX BY BINARY_INTEGER;
            ...
Вы можете использовать атрибут %TYPE для предоставления типа столбца, как показывает следующий пример:
        DECLARE
            TYPE EnameTabTyp IS TABLE OF emp.ename%TYPE
                INDEX BY BINARY_INTEGER;
            ...
После определения типа EnameTabTyp вы можете объявлять таблицы PL/SQL этого типа, например:
        ename_tab  EnameTabTyp;
Идентификатор ename_tab представляет всю таблицу PL/SQL.

Таблица PL/SQL не ограничена, потому что ее первичный ключ может принимать любое значение в интервале допустимых значений для BINARY_INTEGER. Как следствие, вы не можете инициализировать таблицу PL/SQL в ее объявлении. Например, следующее объявление незаконно:

        ename_tab  EnameTabTyp := ('CASEY','STUART','CHU');  --незаконно
Таблицы PL/SQL подчиняются обычным правилам сферы и инстанциации (инстанциация - это создание нового экземпляра программного объекта). В пакете, таблицы PL/SQL инстанциируются при первом обращении к этому пакету, и перестают существовать, когда вы выходите из приложения или заканчиваете сессию базы данных. В блоке или подпрограмме, таблицы PL/SQL инстанциируются при входе в блок или подпрограмму, и перестают существовать, когда вы выходите из блока или подпрограммы.

Как и скалярные переменные, таблицы PL/SQL могут объявляться как формальные параметры процедур и функций. Ограничения, которые применяются к скалярным параметрам, применимы и к таблицам PL/SQL. Приведем несколько пакетированных примеров:

        PACKAGE emp_actions IS
            TYPE EnameTabTyp IS TABLE OF emp.ename%TYPE
                INDEX BY BINARY_INTEGER;
            TYPE SalTabTyp IS TABLE OF emp.sal%TYPE
                INDEX BY BINARY_INTEGER;
            ename_tab  EnameTabTyp;
            sal_tab    SalTabTyp;
            ...
            PROCEDURE hire_batch
                (ename_tab  EnameTabTyp,
                 sal_tab    SalTabTyp,
                 ...);
            PROCEDURE log_names
                (ename_tab  EnameTabTyp,
                 num        BINARY_INTEGER);
            ...
        END emp_actions;
Чтобы определить поведение формальных параметров, вы используете моды параметров, которые обсуждаются в главе 6. Параметры OUT позволяют возвращать значения вызывающей программе при выходе из подпрограммы. Если выход успешен, PL/SQL присваивает фактическим параметрам значения строк. Однако, если вы выходите с необработанным исключением, PL/SQL не присваивает фактическим параметрам значения строк.

Обращение к таблицам PL/SQL

Чтобы обратиться к строке таблицы PL/SQL, вы специфицируете значение первичного ключа, используя синтаксис, напоминающий индексацию массива:

        имя_таблицы_plsql(значение_первичного_ключа)
где значение_первичного_ключа есть значение типа BINARY_INTEGER. Например, чтобы обратиться к третьей строке таблицы PL/SQL ename_tab, вы пишете:
        ename_tab(3) ...
Допустимый диапазон значений BINARY_INTEGER - от -2**31 - 1 до 2**31 - 1, так что значение первичного ключа может быть отрицательным. Например, следующая ссылка законна:
        ename_tab(-5) ...
По поводу исключения, обратитесь к разделу "Использование хост-массивов с таблицами PL/SQL" в главе 8.

Чтобы присвоить конкретной строке таблицы PL/SQL значение выражения PL/SQL, используйте следующий синтаксис:

        имя_таблицы_plsql(значение_первичного_ключа) := выражение_plsql;
В следующем примере вы назначаете сумму переменных salary и increase пятой строке таблицы PL/SQL sal_tab:
        sal_tab(5) := salary + increase;
В следующем примере курсорный цикл FOR используется для загрузки двух таблиц PL/SQL. Курсорный цикл FOR неявно объявляет свой индекс цикла как запись, открывает курсор, ассоциированный с данным запросом, последовательно извлекает строки значений из курсора в поля записи, а затем закрывает курсор. Для более подробной информации о курсорных циклах FOR обратитесь к разделу "Управление курсорами" в главе 4.
        DECLARE
            TYPE EnameTabTyp IS TABLE OF emp.ename%TYPE
                INDEX BY BINARY_INTEGER;
            TYPE SalTabTyp IS TABLE OF emp.sal%TYPE
                INDEX BY BINARY_INTEGER;
            ename_tab  EnameTabTyp;
            sal_tab    SalTabTyp;
            i          BINARY_INTEGER := 0;
            ...
        BEGIN
            -- загрузить имена и оклады сотрудников в таблицы PL/SQL
            FOR emprec IN (SELECT ename, sal FROM emp) LOOP
                i := i + 1;
                ename_tab(i) := emprec.ename;
                sal_tab(i) := emprec.sal;
            END LOOP;
            -- обработать таблицы
            process_sals(ename_tab, sal_tab);
            ...
        END;
В следующем примере используется квалифицированная ссылка для обращения к пакету emp_actions, который вы видели выше в этом разделе:
        DECLARE
            ...
            i          BINARY_INTEGER := 0;
        BEGIN
            -- загрузить имена сотрудников в таблицу PL/SQL
            FOR emprec IN (SELECT ename FROM emp ORDER BY ename) LOOP
                i := i + 1;
                emp_actions.ename_tab(i) := emprec.ename;
            END LOOP;
            -- обработать таблицу PL/SQL
            emp_actions.log_name(emp_actions.ename_tab, i);
            ...
        END;
Пока строке таблицы PL/SQL не присвоено значение, эта строка не существует. При попытке обратиться к неинициализированной строке PL/SQL возбуждает предопределенное исключение NO_DATA_FOUND. Рассмотрим следующий пример:
        DECLARE
            TYPE JobTabTyp IS TABLE OF CHAR(14)
                INDEX BY BINARY_INTEGER;
            job_tab  JobTabTyp;
        BEGIN
            job_tab(1) := 'CLERK';
            IF job_tab(2) = 'CLERK' THEN  -- возбуждает NO_DATA_FOUND
                ...
            END IF;
            ...
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                -- сюда, потому что job_tab(2) не существует
                ...
        END;
Ссылки на строки, подобные job_tab(1), допускаются как фактические параметры в вызовах подпрограмм, но к ним применимы те же ограничения, что и к скалярным переменным.

Поддержка счетчика строк

Вспомним, что размер таблицы PL/SQL не ограничен. Поэтому, если вы хотите поддерживать счетчик строк, вы должны для этой цели объявить переменную. Например, вы могли бы объявить переменную типа INTEGER с именем row_count, в которой будете хранить текущее число строк в вашей таблице PL/SQL.

Что произойдет, если таблица PL/SQL станет слишком велика? Рассмотрим следующий пример:

        DECLARE
            TYPE DateTabTyp IS TABLE OD DATE
                INDEX BY BINARY_INTEGER;
            hiredate_tab  DateTabTyp;
            i  BINARY_INTEGER := 0;
        BEGIN
            /* Инициализировать таблицу PL/SQL. */
            LOOP
                i := i + 1;
                hiredate_tab(i) := SYSDATE;
                -- предложение EXIT WHEN опущено
            END LOOP;
            ...
        END;
В каждой итерации основного цикла к таблице PL/SQL добавляется очередная строка. Цикл не может завершиться, потому что он не содержит предложения EXIT WHEN. В конце концов, PL/SQL переполнит имеющуюся память и возбудит предопределенное исключение STORAGE_ERROR.

Вставка и извлечение строк

Вы должны использовать цикл, чтобы вставлять (INSERT) значения из таблицы PL/SQL в столбец базы данных. Аналогично, вы должны использовать цикл, чтобы извлекать (FETCH) значения из столбца базы данных в таблицу PL/SQL. (Для таблиц PL/SQL не существует потокового интерфейса, подобного тому, который прекомпиляторы ORACLE предоставляют для хост-массивов.) Например, при объявлениях

        DECLARE
            TYPE EmpnoTabTyp IS TABLE OF NUMBER(4)
                INDEX BY BINARY_INTEGER;
            TYPE EnameTabTyp IS TABLE OF CHAR(10)
                INDEX BY BINARY_INTEGER;
            ...
            empno_tab  EmpnoTabTyp;
            ename_tab  EnameTabTyp;
            ...
вы могли бы использовать следующую процедуру, чтобы вставить значения из таблиц PL/SQL в таблицу базы данных emp:
        PROCEDURE insert_emp_data
            (rows       BINARY_INTEGER,
             empno_tab  EmpnoTabTyp,
             ename_tab  EnameTabTyp,
             ...) IS
        BEGIN
            FOR i IN 1..rows LOOP
                INSERT INTO emp (empno, ename, ...)
                    VALUES (empno_tab(i), ename_tab(i), ...);
            END LOOP;
        END;
Аналогично, вы могли бы использовать следующую процедуру, чтобы извлечь все строки из таблицы базы данных emp в таблицы PL/SQL empno_tab и ename_tab:
        PROCEDURE fetch_emp_data
            (rows       OUT BINARY_INTEGER,
             empno_tab  OUT EmpnoTabTyp,
             ename_tab  OUT EnameTabTyp,
             ...) IS
        BEGIN
            rows := 0;
            FOR emprec IN (SELECT * FROM emp) LOOP
                rows := rows + 1;
                empno_tab(rows) := emprec.empno;
                ename_tab(rows) := emprec.ename;
                ...
            END LOOP;
        END;
Однако нельзя ссылаться на таблицы PL/SQL в фразе INTO. Например, следующее предложение SELECT незаконно:
        PROCEDURE fetch_emp_data
            (rows       OUT BINARY_INTEGER,
             empno_tab  OUT EmpnoTabTyp,
             ename_tab  OUT EnameTabTyp,
             ...) IS
        BEGIN
            SELECT empno, ename
                INTO empno_tab, ename_tab  -- незаконно
                FROM emp;
            ...
        END;

Удаление строк

Не существует прямолинейного способа удаления строк из таблицы PL/SQL, потому что предложение DELETE не может применяться для этой цели. Присваивание строке пустого значения, показанное ниже, не приводит к цели, потому что строка остается:

        sal_tab(3) := NULL;
Последующее обращение к этой строке не приведет к исключению NO_DATA_FOUND.

Хотя вы не можете удалять индивидуальных строк из таблиц PL/SQL, есть простой способ удалять такие таблицы целиком. Прежде всего, объявите еще одну таблицу PL/SQL того же типа, и оставьте ее пустой. Позже, когда вы захотите удалить первоначальную таблицу PL/SQL, просто присвойте ей пустую таблицу, как показано в следующем примере:

        DECLARE
            TYPE NumTabTyp IS TABLE OF NUMBER
                INDEX BY BINARY_INTEGER;
            sal_tab    NumTabTyp;
            empty_tab  NumTabTyp;
            ...
        BEGIN
            /* Загрузить таблицу окладов. */
            FOR i IN 1..50 LOOP
                sal_tab(i) := i;
            END LOOP;
            ...
            /* Удалить все строки из таблицы окладов. */
            sal_tab := empty_tab;
            ...
            IF sal_tab(3) = 3 THEN ...  -- возбуждает NO_DATA_FOUND
            ...
        END;

Пользовательские записи

Вы можете использовать атрибут %ROWTYPE, чтобы объявить запись, которая будет представлять строку таблицы базы данных, или строку, извлекаемую курсором. Однако вы не можете специфицировать типы полей в такой записи, или определить свои собственные поля. Составной тип RECORD снимает эти ограничения.

Как вы могли ожидать, объекты типа RECORD называются ЗАПИСЯМИ. В отличие от таблиц PL/SQL, записи имеют уникально поименованные поля, которые могут принадлежать различным типам данных. Например, предположим, что вы имеете различного рода данные о сотруднике, такие как имя, оклад, дата приема и т.п. Эти данные различаются по типам, но все они взаимосвязаны. Запись, содержащая такие поля, как имя, оклад и дата приема сотрудника, помогла бы вам обращаться с этими данными как с логической единицей.

Объявление записей

Как и таблицы PL/SQL, записи должны объявляться за два шага. Сначала вы объявляете (поименованный) тип RECORD, а затем объявляете поьзовательские записи этого типа.

Вы можете объявлять типы RECORD в декларативной части любого блока, подпрограммы или пакета, используя следующий синтаксис:

        TYPE имя_типа IS RECORD
           (имя_поля1 {тип_поля | переменная%TYPE | таблица.столбец%TYPE | таблица%ROWTYPE} [NOT NULL],
           (имя_поля2 {тип_поля | переменная%TYPE | таблица.столбец%TYPE | таблица%ROWTYPE} [NOT NULL],
           ...);
Здесь имя_типа - спецификатор типа, используемый в последующих объявлениях записей этого типа, а тип_поля - любой тип данных, включая RECORD и TABLE. Альтернативно, вы можете использовать атрибут %TYPE или %ROWTYPE, чтобы специфицировать тип данных для поля. В следующем примере объявляется тип RECORD с именем DeptRecTyp:
        DECLARE
            TYPE DeptRecTyp IS RECORD
                (deptno  NUMBER(2) NOT NULL := 20,
                 dname   dept.dname%TYPE,
                 loc     dept.loc%TYPE);
            ...
Заметьте, что объявления полей аналогичны объявлениям переменных. Каждое поле имеет уникальное имя и специфический тип данных. Вы можете добавить ограничение NOT NULL к объявлению любого поля, и тем самым предотвратить присваивание этому полю пустых значений. Поля, объявленные с ограничением NOT NULL, должны быть инициализированы.

После объявления типа DeptRecTyp вы можете объявлять записи этого типа, например:

        dept_rec  DeptRecTyp;
Идентификатор dept_rec представляет целую запись.

В отличие от таблиц PL/SQL, запись может быть инициализирована в своем объявлении, как показывает пример:

        DECLARE
            TYPE TimeTyp IS RECORD
                (second  SMALLINT := 0,
                 minute  SMALLINT := 0,
                 hour    SMALLINT := 0);
            ...
Когда вы объявите запись типа TimeTyp, все три ее поля получат нулевые начальные значения.

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

Как и скалярные переменные, пользовательские записи могут объявляться как формальные параметры процедур и функций. Пример:

        PACKAGE emp_actions IS
            TYPE EmpRecTyp IS RECORD
                (empno     NUMBER(4) NOT NULL := 1001,
                 ename     CHAR(10),
                 job       CHAR(14),
                 mgr       NUMBER(4),
                 hiredate  DATE,
                 sal       NUMBER(7,2),
                 comm      NUMBER(7,2),
                 deptno    NUMBER(4));
            ...
            PROCEDURE hire_employee (emp_rec EmpRecTyp);
            ...
        END emp_actions;
Чтобы определить поведение формальных параметров, вы используете моды параметров, которые обсуждаются в главе 6. Параметры OUT позволяют возвращать значения вызывающей программе при выходе из подпрограммы. Если выход успешен, PL/SQL присваивает фактическим параметрам значения строк. Однако, если вы выходите с необработанным исключением, PL/SQL не присваивает фактическим параметрам значения строк.

Обращение к записям

Чтобы обращаться к индивидуальным полям в записи, вы используете квалифицированные ссылки:

        имя_записи.имя_поля
Например, вы обращаетесь к полю ename в записи emp_rec так:
        emp_rec.ename ...
Вы можете присвоить конкретному полю записи значение выражения PL/SQL, используя следующий синтаксис:
        имя_записи.имя_поля := выражение_plsql;
В следующем примере имя сотрудника преобразуется в прописные буквы:
        emp_rec.ename := UPPER(emp_rec.ename);
Вместо присваивания значений отдельным полям записи можно присвоить значения сразу всем полям в записи. Это можно сделать двумя способами. Во-первых, вы можете присвоить одну запись другой, если обе записи принадлежат одному и тому же типу. Например, при объявлениях
        DECLARE
            TYPE DeptRecTyp IS RECORD (...);
            dept_rec1  DeptRecTyp;
            dept_rec2  DeptRecTyp;
            ...
следующее присваивание законно:
        BEGIN
            ...
            dept_rec1 := dept_rec2;
Во-вторых, вы можете присвоить записи список значений столбцов при помощи предложения SELECT или FETCH, как показывает следующий пример. Вы должны лишь обеспечить, чтобы имена столбцов появлялись в том же порядке, что и поля в вашей записи.
        DECLARE
            TYPE DeptRecTyp IS RECORD
                (deptno    NUMBER(2),
                 dname     CHAR(14),
                 loc       CHAR(13));
            dept_rec  DeptRecTyp;
            ...
        BEGIN
            SELECT deptno, dname, loc INTO dept_rec FROM dept
                WHERE deptno = 30;
            ...
        END;

Ограничения

Даже при полном совпадении полей, записи различного типа нельзя присваивать друг другу. Более того, пользовательская запись и запись %ROWTYPE всегда принадлежат различным типам, как показывает следующий пример:

        DECLARE
            TYPE DeptRecTyp IS RECORD
                (deptno    NUMBER(2),
                 dname     CHAR(14),
                 loc       CHAR(13));
            dept_rec1  DeptRecTyp;
            dept_rec2  dept%ROWTYPE;
            ...
        BEGIN
            ...
            dept_rec1 := dept_rec2;  -- незаконно
Нельзя присваивать записи список значений, используя оператор присваивания. Так, следующий синтаксис незаконен:
        имя_записи := (значение1,значение2, значение3, ...); --незаконно
Кроме того, записи нельзя проверять на равенство или неравенство. Например, следующее условие IF незаконно:
        IF dept_rec1 = dept_rec2 THEN  -- незаконно
            ...
        END IF;

Вложенные записи

PL/SQL позволяет вам объявлять и ссылаться на ВЛОЖЕННЫЕ записи. Иными словами, запись может быть компонентой другой записи, как показывает следующий пример:

        DECLARE
            TYPE TimeTyp IS RECORD
                (minute  SMALLINT,
                 hour    SMALLINT);
            TYPE MeetingTyp IS RECORD
                (day      DATE,
                 time     TimeTyp,      -- вложенная запись
                 place    CHAR(20),
                 purpose  CHAR(50));
            TYPE PartyTyp IS RECORD
                (day   DATE,
                 time  TimeTyp,         -- вложенная запись
                 loc   CHAR(15));
            meeting  MeetingTyp;
            seminar  MeetingTyp;
            party    PartyTyp;
            ...
        BEGIN
            meeting.day := '26-JUN-91';
            meeting.time.minute := 45;
            meeting.time.hour := 10;
            ...
        END;
Следующий пример показывает, что вы можете присваивать одну вложенную запись другой, если обе они принадлежат одному типу:
        seminar.time := meeting.time;
Такие присваивания разрешаются даже в тех случаях, когда содержащие записи относятся к разным типам данных, как показывает следующий пример:
        party.time := meeting.time;

Преимущества записей

Тип RECORD позволяет вам коллекционировать информацию об атрибутах объекта. Такой информацией легко манипулировать, потому что вы можете ссылаться на объект в целом. В следующем примере, вы собираете бухгалтерские цифры из таблиц базы данных с именами assets и liabilities, а затем применяете сравнительный анализ, чтобы сравнить производительность двух дочерних компаний:

        DECLARE
            TYPE FiguresTyp IS RECORD
                (cash                   REAL,
                 marketable_securities  REAL,
                 accounts_receivable    REAL,
                 inventories            REAL,
                 accounts_payable       REAL,
                 notes                  REAL,
                 employment_costs       REAL,
                 accrued_taxes          REAL,
                 dividends_payable      REAL,
                 short_term_debt        REAL);
            sub1_figs FiguresTyp;
            sub2_figs FiguresTyp;
            ...
            FUNCTION acid_test (figs FiguresTyp) RETURN REAL IS
                current_liabilities  REAL;
            BEGIN
                current_liabilities := figs.accounts_payable +figs.notes
                    + figs.employment_costs + figs.accrued_taxes
                    + figs.dividends_payable + figs.short_term_debt;
                RETURN (figs.cash + figs.marketable_securities
                    + figs.accounts_receivable) / current_liabilities;
            END acid_test;
            ...
        BEGIN
            SELECT cash, mkt_sec, accts_rec, ... INTO sub1_figs
                FROM assets, liabilities
                WHERE assets.sub = 1 AND liabilities.sub = 1;
            SELECT cash, mkt_sec, accts_rec, ... INTO sub2_figs
                FROM assets, liabilities
                WHERE assets.sub = 2 AND liabilities.sub = 2;
            ...
            IF acid_test(sub1_figs) > acid_test(sub2_figs) THEN ...
            ...
        END;
        Заметьте, как легко передать собранные цифры функции  acid_test,
        которая вычисляет финансовый коэффициент.