ГЛАВА 2

        ----------------------------------------------------------------

        ОСНОВЫ


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


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











































                                                             Основы  2-1


----------------

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

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

            *  прописные и строчные буквы A .. Z, a .. z

            *  цифры 0 .. 9

            *  символы табуляция, пробел и возврат каретки ("пропуски")

            *  символы ()+-*/<>=!~;:.'@%,"#$^&_|{}?[]

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


----------------

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

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

            *  разделители (простые и составные символы)

            *  идентификаторы, в том числе зарезервированные слова

            *  литералы

            *  комментарии

        Например, строка

        bonus := salary * 0.10;  -- вычислить премию

        содержит следующие лексические единицы:

            *  идентификаторы bonus и salary

            *  составной символ :=

            *  простые символы * и ;

            *  числовой литерал 0.10

            *  комментарий -- вычислить премию

        Для  улучшения  читабельности  вы  можете  разделять лексические
        единицы  пропусками.   На  самом  деле,  вы  обязаны   разделять
        соседние  идентификаторы  пропусками  или  знаками   пунктуации.
        Например,    следующая    строка    незаконна,    потому     что
        зарезервированные слова END и IF соединены:

        IF x > y THEN high := x; ENDIF;  -- незаконно




2-2  Руководство пользователя и справочник по PL/SQL


        Однако  вы  не  можете  вставлять  пропуски  внутри  лексических
        единиц,  за  исключением  строковых  литералов  и  комментариев.
        Например,  следующая  строка  незаконна,  потому  что  составной
        символ для операции присваивания (:=) разъединен:

        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
        специальный  смысл.   Например,  вы  используете разделители для
        представления  арифметических  операций,  таких  как  сложение и
        вычитание.

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

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

        +       оператор сложения

        -       оператор вычитания/отрицания

        *       оператор умножения

        /       оператор деления

        =       оператор сравнения

        <       оператор сравнения

        >       оператор сравнения

        (       ограничитель выражения или списка

        )       ограничитель выражения или списка

        ;       терминатор предложения

        %       индикатор атрибута

        ,       разделитель элементов

        .       селектор компоненты

        @       индикатор удаленного доступа

        '       ограничитель символьной строки

        "       ограничитель идентификатора

        :       индикатор хост-переменной

                                                             Основы  2-3


Составные символы

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

        **      оператор возведения в степень

        <>      оператор сравнения

        !=      оператор сравнения

        ~=      оператор сравнения

        ^=      оператор сравнения

        <=      оператор сравнения

        >=      оператор сравнения

        :=      оператор присваивания

        =>      оператор ассоциации

        ..      оператор интервала

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

        <<      ограничитель метки

        >>      ограничитель метки

        --      индикатор однострочного комментария

        /*      (начальный) ограничитель многострочного комментария

        */      (конечный) ограничитель многострочного комментария


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

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

        X
        t2
        phone#
        credit_limit
        LastName
        oracle$number

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

        mine&yours      -- незаконный амперсенд
        debit-amount    -- незаконный дефис
        on/off          -- незаконная косая черта
        user id         -- незаконный пробел

2-4  Руководство пользователя и справочник по PL/SQL


        Следующие    примеры    показывают,    что    использование    в
        идентификаторах знаков  доллара, подчеркиваний  и знаков  номера
        законно:

        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.






                                                             Основы  2-5


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

        Идентификаторы, глобально  объявленные в  пакете 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 вместо базовой таблицы.










2-6  Руководство пользователя и справочник по PL/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
















                                                             Основы  2-7


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

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

        '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,  которое  обозначает  отсутствие,
        неизвестность или  неприменимость значения.   Не забывайте,  что
        булевские литералы НЕ являются строками.












2-8  Руководство пользователя и справочник по PL/SQL


Комментарии
-----------

        Компилятор  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,  потому что  в этом  случае символы конца
        строки игнорируются, и, как следствие, однострочный  комментарий
        растянется до конца блока, а не только до конца строки.  Поэтому
        в таких случаях используйте многострочные комментарии.


                                                             Основы  2-9


----------------

Типы данных

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

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

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

        ---------------------------------------------------------------¬
        ¦                                                              ¦
        ¦                     Типы данных PL/SQL                       ¦
        ¦                                                              ¦
        ¦ -------------------------------------¬ ---------------------¬¦
        ¦ ¦          Скалярные типы            ¦ ¦   Составные типы   ¦¦
        ¦ ¦ -------------------¬ ------------¬ ¦ ¦---------¬ --------¬¦¦
        ¦ ¦ ¦ BINARY_INTEGER   ¦ ¦ CHAR      ¦ ¦ ¦¦ RECORD ¦ ¦ TABLE ¦¦¦
        ¦ ¦ ¦ DEC              ¦ ¦ CHARACTER ¦ ¦ ¦L--------- L--------¦¦
        ¦ ¦ ¦ DECIMAL          ¦ ¦ LONG      ¦ ¦ ¦                    ¦¦
        ¦ ¦ ¦ DOUBLE PRECISION ¦ ¦ LONG RAW  ¦ ¦ L---------------------¦
        ¦ ¦ ¦ FLOAT            ¦ ¦ RAW       ¦ ¦                       ¦
        ¦ ¦ ¦ INT              ¦ ¦ ROWID     ¦ ¦                       ¦
        ¦ ¦ ¦ INTEGER          ¦ ¦ STRING    ¦ ¦                       ¦
        ¦ ¦ ¦ NATURAL          ¦ ¦ VARCHAR   ¦ ¦                       ¦
        ¦ ¦ ¦ NUMBER           ¦ ¦ VARCHAR2  ¦ ¦                       ¦
        ¦ ¦ ¦ NUMERIC          ¦ L------------ ¦                       ¦
        ¦ ¦ ¦ POSITIVE         ¦ -------¬      ¦                       ¦
        ¦ ¦ ¦ REAL             ¦ ¦ DATE ¦      ¦                       ¦
        ¦ ¦ ¦ SMALLINT         ¦ L-------      ¦                       ¦
        ¦ ¦ L------------------- ----------¬   ¦                       ¦
        ¦ ¦                      ¦ BOOLEAN ¦   ¦                       ¦
        ¦ ¦                      L----------   ¦                       ¦
        ¦ L-------------------------------------                       ¦
        L---------------------------------------------------------------


        В этом разделе описываются скалярные типы; составные типы данных
        обсуждаются в этой главе позже.













2-10  Руководство пользователя и справочник по PL/SQL


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 (0 .. 2147483647)

            *  POSITIVE (1 .. 2147483647)

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

NUMBER
------

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

        NUMBER[(точность, масштаб)]

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

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

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









                                                            Основы  2-11


Подтипы NUMBER

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

            *  DEC
            *  DECIMAL
            *  DOUBLE PRECISION
            *  FLOAT
            *  INT
            *  INTEGER
            *  NUMERIC
            *  REAL
            *  SMALLINT

        Вы можете  использовать эти  подтипы для  совместимости с типами
        данных 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).











2-12  Руководство пользователя и справочник по PL/SQL


Подтипы CHAR

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

            *  CHARACTER
            *  STRING

        Вы можете  использовать эти  подтипы для  совместимости с типами
        данных 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.






                                                            Основы  2-13


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.













2-14  Руководство пользователя и справочник по PL/SQL


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  включают
        время дня,  исчисляемое в  секундах после  полуночи.  Компонента
        даты, если она отсутствует, принимает по умолчанию значение даты
        на первый  день текущего  месяца; компонента  времени, если  она
        отсутствует,  принимает  по  умолчанию  время на полночь текущей
        (или умалчиваемой) даты.


















                                                            Основы  2-15


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.





2-16  Руководство пользователя и справочник по PL/SQL


----------------

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

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

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

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

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

                Куда
               г===========T=======T=========T========T===========¬
               ¦CHAR       ¦DATE   ¦NUMBER   ¦RAW     ¦ROWID      ¦
        г======+===========+=======+=========+========+===========¦
Откуда  ¦CHAR  ¦           ¦TO_DATE¦TO_NUMBER¦HEXTORAW¦CHARTORAWID¦
        ¦------+-----------+-------+---------+--------+-----------¦
        ¦DATE  ¦TO_CHAR    ¦       ¦         ¦        ¦           ¦
        ¦------+-----------+-------+---------+--------+-----------¦
        ¦NUMBER¦TO_CHAR    ¦TO_DATE¦         ¦        ¦           ¦
        ¦------+-----------+-------+---------+--------+-----------¦
        ¦RAW   ¦RAWTOHEX   ¦       ¦         ¦        ¦           ¦
        ¦------+-----------+-------+---------+--------+-----------¦
        ¦ROWID ¦ROWIDTOCHAR¦       ¦         ¦        ¦           ¦
        L======¦===========¦=======¦=========¦========¦===========-


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






















                                                            Основы  2-17


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

        Когда это  имеет смысл,  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,  если  необходимо,  преобразует  значение из типа данных
        переменной в тип данных целевого столбца.
























2-18  Руководство пользователя и справочник по PL/SQL


        Если PL/SQL  не может  определить, какое  неявное преобразование
        необходимо, вы получите ошибку  компиляции.  В таких случаях  вы
        должны использовать явные  функции преобразования типов  данных.
        На рис.2-3 показано,  какие неявные преобразования  типов данных
        может выполнять PL/SQL.

Рис.2-3
Неявные преобразования типов данных

                 Куда
                 г=======T====T====T====T======T====T=====T========¬
                 ¦BINARY_¦CHAR¦DATE¦LONG¦NUMBER¦RAW ¦ROWID¦VARCHAR2¦
                 ¦INTEGER¦    ¦    ¦    ¦      ¦    ¦     ¦        ¦
        г========+=======+====+====+====+======+====+=====+========¦
Откуда  ¦BINARY_ ¦       ¦ Да ¦    ¦ Да ¦  Да  ¦    ¦     ¦   Да   ¦
        ¦INTEGER ¦       ¦    ¦    ¦    ¦      ¦    ¦     ¦        ¦
        ¦--------+-------+----+----+----+------+----+-----+--------¦
        ¦CHAR    ¦  Да   ¦    ¦ Да ¦ Да ¦  Да  ¦ Да ¦ Да  ¦   Да   ¦
        ¦--------+-------+----+----+----+------+----+-----+--------¦
        ¦DATE    ¦       ¦ Да ¦    ¦ Да ¦      ¦    ¦     ¦   Да   ¦
        ¦--------+-------+----+----+----+------+----+-----+--------¦
        ¦LONG    ¦       ¦ Да ¦    ¦    ¦      ¦ Да ¦     ¦   Да   ¦
        ¦--------+-------+----+----+----+------+----+-----+--------¦
        ¦NUMBER  ¦  Да   ¦ Да ¦    ¦ Да ¦      ¦    ¦     ¦   Да   ¦
        ¦--------+-------+----+----+----+------+----+-----+--------¦
        ¦RAW     ¦       ¦ Да ¦    ¦ Да ¦      ¦    ¦     ¦   Да   ¦
        ¦--------+-------+----+----+----+------+----+-----+--------¦
        ¦ROWID   ¦       ¦ Да ¦    ¦    ¦      ¦    ¦     ¦   Да   ¦
        ¦--------+-------+----+----+----+------+----+-----+--------¦
        ¦VARCHAR2¦  Да   ¦ Да ¦ Да ¦ Да ¦  Да  ¦ Да ¦ Да  ¦        ¦
        L========¦=======¦====¦====¦====¦======¦====¦=====¦========-


        Вы   сами   должны   гарантировать   преобразуемость   значений.
        Например,  PL/SQL   может  преобразовать   значение  типа   CHAR
        '02-JUN-92' в значение типа DATE, но он не может преобразовать в
        тип DATE символьную  строку 'YESTERDAY'.  Аналогично,  PL/SQL не
        может  преобразовать  в  тип  NUMBER  значение  CHAR, содержащее
        нецифровые символы.
























                                                            Основы  2-19


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

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

Значения 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.  Каждая пара
        символов    в    значении    переменной    должна   представлять
        шестнадцатеричный эквивалент  двоичного байта.   Если какой-либо
        из символов не представляет собой шестнадцатеричную цифру, будет
        возбуждено исключение.

















2-20  Руководство пользователя и справочник по PL/SQL


----------------

Объявления

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

        Вы можете объявлять переменные и константы в декларативной части
        любого  блока  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.  Константа ДОЛЖНА  быть
        инициализирована в  своем объявлении;  иначе вы  получите ошибку
        компиляции.










                                                            Основы  2-21


Использование 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 изменится соответственно во время
        выполнения.











2-22  Руководство пользователя и справочник по PL/SQL


        Заметим, однако, что ограничение столбца 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;









                                                            Основы  2-23


        Нельзя  включать  выражений   инициализации  в  объявления   тех
        переменных, которые используют %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);  -- незаконно














2-24  Руководство пользователя и справочник по PL/SQL


Алиасы

        Каждый элемент списка, извлекаемого из курсора, ассоциированного
        с    атрибутом    %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;









                                                            Основы  2-25


----------------

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

        Одни  и  те  же  соглашения  об  именах  действительны  для всех
        программных  объектов  и   единиц  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;      -- незаконное повторение имени

        О  правилах  сферы,  действующих  для  переменных  и параметров,
        смотрите в разделе "Сфера и видимость".











2-26  Руководство пользователя и справочник по PL/SQL


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

        Как  и  прочие  идентификаторы,  имена  переменных  и параметров
        нечевствительны к регистру букв.  Например, 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;

        Однако лучшей практикой  программирования было бы  переименовать
        такую переменную или формальный параметр.













                                                            Основы  2-27


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

        Имена  столбцов  базы  данных  имеют  преимущество  над  именами
        локальных   переменных   и   формальных   параметров.  Например,
        следующее  предложение  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; 2-28 Руководство пользователя и справочник по PL/SQL ---------------- Сфера и видимость Ссылки на идентификатор разрешаются согласно его сфере и видимости. СФЕРА идентификатора - это та область программной единицы (блока, подпрограммы или пакета), из которой вы можете ссылаться на этот идентификатор. Идентификатор называется ВИДИМЫМ в тех областях, из которых вы можете ссылаться на него, используя неквалицифированное имя. Например, идентификаторы, объявленные в блоке 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; 2-30 Руководство пользователя и справочник по PL/SQL Или, как показывает следующий пример, квалификатором может быть имя окружающей подпрограммы: 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; Выражение, стоящее справа от оператора присваивания, может быть сколь угодно сложным, но его результат должен иметь такой же тип данных, что и тип переменной, или быть преобразуемым в этот тип. Основы 2-31 Булевские значения ------------------ Булевской переменной можно присвоить лишь значения 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. 2-32 Руководство пользователя и справочник по PL/SQL ---------------- Выражения и сравнения Выражения конструируются из операндов и операторов. ОПЕРАНД - это переменная, константа, литерал или вызов функции, поставляющий значение выражению. Пример простого арифметического выражения: -x / 2 Унарные операторы, такие как оператор отрицания (-), действуют на один операнд; бинарные операторы, такие как оператор деления (/), действуют на два операнда. В PL/SQL нет тернарных операторов. Простейшее выражение состоит из единственной переменной, которая непосредственно поставляет свое значение. PL/SQL ВЫЧИСЛЯЕТ выражение (т.е. находит его текущее значение), комбинируя значения операндов так, как это предписано операторами. В результате всегда получается единственное значение определенного типа данных. PL/SQL определяет этот тип данных, изучая выражение и контекст, в котором оно появляется. Старшинство операторов ---------------------- Операции внутри выражения выполняются в определенном порядке, в зависимости от их старшинства (приоритета). На рис.2-5 показан умалчиваемый порядок операций от первой к последней (сверху вниз). Рис.2-5 Порядок операций -----------------------------T---------------------------------¬ ¦ Оператор ¦ Операция ¦ +----------------------------+---------------------------------+ ¦ **, NOT ¦ возведение в степень, ¦ ¦ ¦ логическое отрицание ¦ +----------------------------+---------------------------------+ ¦ +, - ¦ тождественность, отрицание ¦ +----------------------------+---------------------------------+ ¦ *, / ¦ умножение, деление ¦ +----------------------------+---------------------------------+ ¦ +, -, || ¦ сложение, вычитание, ¦ ¦ ¦ конкатенация ¦ +----------------------------+---------------------------------+ ¦ =, !=, <, >, <=, >=, ¦ сравнение ¦ ¦ IS NULL, LIKE, BETWEEN, IN ¦ ¦ +----------------------------+---------------------------------+ ¦ AND ¦ конъюнкция ¦ +----------------------------+---------------------------------+ ¦ OR ¦ включение ¦ L----------------------------+---------------------------------- Основы 2-33 Операторы с более высоким приоритетом выполняются первыми. Например, оба следующих выражения дают результат 8, потому что деление имеет более высокий приоритет, чем сложение: 5 + 12 / 4 12 / 4 + 5 Для операторов одного и того же приоритета не существует никакого специального порядка выполнения. Вы можете использовать скобки, чтобы управлять порядком вычисления выражения. Например, следующее выражение дает 7, а не 11, потому что скобки перекрывают умалчиваемый порядок: (8 + 6) / 2 В следующем примере вычитание выполняется раньше деления, потому что наиболее глубоко вложенное подвыражение всегда вычисляется первым: 100 + (20 / 5 + (7 - 3)) Как показывает следующий пример, вы всегда можете использовать скобки для улучшения читабельности, даже если в них нет необходимости: (salary * 0.05) + (commission * 0.25) 2-34 Руководство пользователя и справочник по PL/SQL Логические операторы -------------------- Логические операторы AND, OR и NOT вычисляются согласно логике трех состояний, иллюстрируемой таблицами истинности на рис.2-6. AND и OR - бинарные операторы; NOT - унарный оператор. Рис.2-6 Таблицы истинности г---------T---------T---------¬ NOT ¦ TRUE ¦ FALSE ¦ NULL ¦ -=========+=========+=========+=========¦ ¦ ¦ FALSE ¦ TRUE ¦ NULL ¦ L---------¦---------+---------+---------- г---------T---------T---------¬ AND ¦ TRUE ¦ FALSE ¦ NULL ¦ -=========+=========+=========+=========¦ ¦ TRUE ¦ TRUE ¦ FALSE ¦ NULL ¦ +---------+---------+---------+---------+ ¦ FALSE ¦ FALSE ¦ FALSE ¦ FALSE ¦ +---------+---------+---------+---------+ ¦ NULL ¦ NULL ¦ FALSE ¦ NULL ¦ L---------¦---------+---------+---------- г---------T---------T---------¬ OR ¦ TRUE ¦ FALSE ¦ NULL ¦ -=========+=========+=========+=========¦ ¦ TRUE ¦ TRUE ¦ TRUE ¦ TRUE ¦ +---------+---------+---------+---------+ ¦ FALSE ¦ TRUE ¦ FALSE ¦ NULL ¦ +---------+---------+---------+---------+ ¦ NULL ¦ TRUE ¦ NULL ¦ NULL ¦ L---------¦---------+---------+---------- Как показывают таблицы истинности, 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. Основы 2-35 Операторы сравнения ------------------- Операторы сравнения сравнивают одно выражение с другим. Результатом сравнения всегда является булевское значение 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' 2-36 Руководство пользователя и справочник по PL/SQL Оператор 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. Основы 2-37 Булевские выражения ------------------- 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. 2-38 Руководство пользователя и справочник по PL/SQL Календарные Вы можете сравнивать значения дат. Такие сравнения - хронологические: одна дата больше другой, если она более поздняя. Например, при присваиваниях 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 ... Основы 2-39 Обработка пустых значений ------------------------- Чтобы избежать некоторых общих ошибок, держите в голове следующие правила: * сравнения, в которых участвует NULL, всегда дают NULL * применение NOT к значению NULL дает NULL * в предложениях условного управления, если условие дает NULL, соответствующая группа предложений не выполняется В следующем примере, вы могли бы ожидать, что ряд предложений будет выполнен, потому что 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 работают одинаково. 2-40 Руководство пользователя и справочник по PL/SQL Строки нулевой длины 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 будут одинаковыми. Основы 2-41 Если ее третий аргумент есть 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 2-42 Руководство пользователя и справочник по PL/SQL Функции сообщений об ошибках ---------------------------- Две функции, 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 возвращает сообщение, ассоциированное с этим номером ошибки. Основы 2-43 Числовые функции ---------------- Числовые функции принимают числовые аргументы и возвращают числовые значения. Трансцендентные функции включают тригонометрические, логарифмические и экспоненциальные функции. Обычные тригонометрические функции (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. 2-44 Руководство пользователя и справочник по PL/SQL 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 может быть отрицательным, что позволяет обнулять цифры десятков, сотен и т.п. Основы 2-45 Символьные функции ------------------ Символьные функции принимают символьные аргументы. Некоторые символьные функции возвращают символьные значения, остальные возвращают числовые значения. Функции, возвращающие символьные значения, всегда возвращают значение типа 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. 2-46 Руководство пользователя и справочник по PL/SQL 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 не задано, подразумевается пробел. Основы 2-47 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. 2-48 Руководство пользователя и справочник по PL/SQL 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. Основы 2-49 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, в которой все буквы преобразованы в прописные. 2-50 Руководство пользователя и справочник по PL/SQL Функции преобразования ---------------------- Функции преобразования конвертируют значение из одного типа данных в другой. 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 WE8PC850 IBM 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. Основы 2-51 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 специфицирует следующие символы, которые возвращаются элементами числового формата: * десятичный разделитель (обозначенный ниже как d) * групповой разделитель (обозначенный ниже как g) * местный символ валюты * международный символ валюты Этот аргумент имеет следующую форму: 'NLS_NUMERIC_CHARACTERS = ''dg'', NLS_CURRENCY = ''текст'', NLS_ISO_CURRENCY = ''текст'' ' Заметьте, что внутри строки, заключенной в апострофы, каждый апостроф представляется двумя апострофами подряд. Если вы опустите nlsparms, то TO_CHAR использует умалчиваемые значения соответствующих параметров для текущей сессии. 2-52 Руководство пользователя и справочник по PL/SQL 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) (продолжение на следующей странице) Основы 2-53 Модель формата Описание ---------------------------------------------------------------- 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. 2-54 Руководство пользователя и справочник по PL/SQL 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. Модель числового формата состоит из элементов формата, приведенных на следующей таблице: Элемент Пример Описание ---------------------------------------------------------------- 9 9999 значащая цифра 0 0999 ведущий нуль (вместо пробела) $ $999 ведущий знак доллара B B999 ведущий пробел (вместо нуля) MI 999MI хвостовой знак минус S S999 ведущий знак (плюс или минус) PR 999PR отрицательные значения в угловых скобках D 99D99 десятичный символ G 9G99 разделитель групп C C999 символ валюты в стандарте ISO L L999 местный символ валюты , 9,999 запятая . 9.999 точка V 999V99 умножение на 10 в степени n, где n - число девяток после V EEEE 9.99EEEE научная нотация RN,rn RN римское числительное в верхнем или нижнем регистре Основы 2-55 Строка str должна представлять действительное число. Аргумент nlsparms специфицирует следующие символы, которые возвращаются элементами числового формата: * десятичный разделитель (обозначенный ниже как d) * групповой разделитель (обозначенный ниже как g) * местный символ валюты * международный символ валюты Этот аргумент имеет следующую форму: '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. 2-56 Руководство пользователя и справочник по PL/SQL 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 Юкон, дневное время Основы 2-57 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.) Если формат опущен, компонента времени удаляется из даты, т.е. осуществляется усечение на ближайший день. 2-58 Руководство пользователя и справочник по PL/SQL Смешанные функции ----------------- 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. Основы 2-59 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. Эта функция не имеет аргументов. 2-60 Руководство пользователя и справочник по PL/SQL 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. Основы 2-61 ---------------- Таблицы 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. 2-62 Руководство пользователя и справочник по PL/SQL В следующем примере вы объявляете тип 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 инстанциируются при входе в блок или подпрограмму, и перестают существовать, когда вы выходите из блока или подпрограммы. Основы 2-63 Как и скалярные переменные, таблицы 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. 2-64 Руководство пользователя и справочник по PL/SQL Чтобы присвоить конкретной строке таблицы 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; Основы 2-65 В следующем примере используется квалифицированная ссылка для обращения к пакету 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), допускаются как фактические параметры в вызовах подпрограмм, но к ним применимы те же ограничения, что и к скалярным переменным. 2-66 Руководство пользователя и справочник по PL/SQL Поддержка счетчика строк ------------------------ Вспомним, что размер таблицы 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. Основы 2-67 Вставка и извлечение строк -------------------------- Вы должны использовать цикл, чтобы вставлять (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; 2-68 Руководство пользователя и справочник по PL/SQL Однако нельзя ссылаться на таблицы 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; Основы 2-69 ---------------- Пользовательские записи Вы можете использовать атрибут %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, должны быть инициализированы. 2-70 Руководство пользователя и справочник по PL/SQL После объявления типа 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 не присваивает фактическим параметрам значения строк. Основы 2-71 Обращение к записям ------------------- Чтобы обращаться к индивидуальным полям в записи, вы используете квалифицированные ссылки: имя_записи.имя_поля Например, вы обращаетесь к полю 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; 2-72 Руководство пользователя и справочник по PL/SQL Ограничения Даже при полном совпадении полей, записи различного типа нельзя присваивать друг другу. Более того, пользовательская запись и запись %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; Основы 2-73 Вложенные записи ---------------- 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; 2-74 Руководство пользователя и справочник по PL/SQL Преимущества записей -------------------- Тип 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, которая вычисляет финансовый коэффициент.