SQL для начинающих

         

Атомарность



Атомарность

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

Что в имени твоем?

Название дополнения SQL — постоянно хранимые модули (persistent stored modules) — очень метко описывает их назначение.

Да вы уже и сами могли догадаться. Если слово модуль вам неизвестно, освежите в памяти материал главы 15. По логике хранимый модуль должен являться чем-то таким, что находится в некотором месте до тех пор, пока не потребуется. Кроме того, постоянно хранимый модуль должен быть чем-то, что находится под рукой в течение определенного периода времени. Вот, собственно, и все, о чем рассказывается в этой главе.

Вы почти угадали, хотя логика немного увела вас в сторону. В этой главе описываются подобные модули. Но постоянно хранимые модули больше связаны с другими возможностями SQL. В SQL:2OO3 огромное количество постоянно хранимых модулей содержат необходимые функции, которые следовало включить еще в SQL-92, но этого не произошло. Такие функции значительно повышают мощность и полезность SQL, и они должны были где-то находиться. Некоторые из них действительно хранятся под своими именами (в частности, хранимые функции и хранимые процедуры). Ладно, довольно логики. Важно лишь, что эти новые средства существуют и работают.

Что если операции вставки в таблицы Students (студенты) и Roster (расписание) произошли, а в результате вмешательства постороннего пользователя операция вставки в таблицу Receivable (плата за учебу) не выполнилась. Получится, что студент будет зачислен, но счет за обучение ему выписан не будет. Такие ошибки могут слишком дорого обойтись университету. Для предотвращения развития событий по данному сценарию необходимо ввести концепцию атомарности. Атомарная команда является неделимой. Она либо выполняется целиком, либо не выполняется вовсе. Простые команды SQL атомарны по своей природе. Другое дело — составные команды SQL. Однако и составную команду тоже можно определить атомарной. В приведенном ниже примере составная команда SQL становится безопасной благодаря введению атомарности.




void main {

    EXEC SQL

        BEGIN ATOMIC

            INSERT INTO students (StudentID, Fname, Lname)

                VALUES (:sid, :sfname, :sid) ;

            INSERT INTO roster (ClassID, Class, StudentID)

                VALUES (:cid, :cname, :sid) ;

            INSERT INTO receivable (StudentID, Class, Fee)

                VALUES (:sid, :cname, :cfee) ;

        END ;

/* Проверка значения SQLSTATE на код ошибки */

}



Ключевые слова ATOMIC после BEGIN гарантируют выполнение всей команды полностью, а в случае возникновения ошибки происходит откат к исходному состоянию базы данных.


CASE...END CASE



CASE...END CASE

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



Действие и эффект обработчика



Действие и эффект обработчика

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

CONTINUE. Выполнение команды, следующей после команды, инициировавшей действие обработчика.

EXIT. Выход из составной команды, содержащей обработчик, и выполнение следующей команды.

UNDO. Отмена всех предыдущих команд составной и выполнение следующей команды.

Эффект CONTINUE лучше всего применять в том случае, если обработчик способен устранить любую проблему, вызвавшую его. Эффект EXIT применяется, если обработчику не под силу исправить проблему, но нет необходимости отменять изменения, сделанные составной командой. Эффект UNDO позволяет вернуться в состояние до выполнения составной команды. Рассмотрим следующий пример:

    BEGIN ATOMIC

        DECLARE constraint_violation CONDITION

            FOR SQLSTATE VALUE '23000' ;

        DECLARE UNDO HANDLER

            FOR constraint_violation

RESIGNAL ;

        INSERT INTO students (StudentID, Fname, Lname)

            VALUES (:sid, sfname, :slname) ;

        INSERT INTO roster (ClassID, Class, StudentID)

            VALUES (:sid, cname, :sid) ;

    END ;

Если выполнение какой-либо из двух команд INSERT вызывает нарушение некоторого ограничения, например, в результате добавления записи с первичным ключом, уже присутствующим в таблице, в параметр SQLSTATE помещается значение 23000 и возникает состояние constraint_violation. Обработчик такого события отменяет изменения, внесенные в таблицы командами INSERT. Команда RESIGNAL возвращает управление процедуре, вызвавшей процедуру обработчика.

После успешного выполнения обеих команд INSERT следующей выполняется команда за ключевым словом END.

Помни: Ключевое слово ATOMIC является обязательным в случае эффекта UNDO. Это не распространяется на обработчики с эффектами CONTINUE или EXIT.



FOR...DO...END FOR



FOR...DO...END FOR

Цикл FOR в SQL объявляет и открывает курсор, выполняет выборку строк курсора, выполняет команды тела цикла FOR для каждой строки, а затем закрывает курсор. Такой цикл позволяет построчно обрабатывать данные в SQL без обращения к базовому языку. Если реализация SQL поддерживает циклы FOR, их можно использовать в качестве альтернативы: курсорам, описанным в главе 18. Ниже приведен пример цикла FOR.

FOR vcount AS Cursl CURSOR FOR

SELECT AsteroidID FROM asteroid

DO

    UPDATE asteroid SET Description = 'stony iron1

        WHERE CURRENT OF Cursl ;

END FOR

В данном примере происходит обновление каждой строки таблицы Asteroid путем ввода 'stony iron' в поле Description. Такой способ ввода данных очень быстрый, но не совсем правильный. Вероятно, следовало бы вначале проверить спектральные характеристики астероидов, а уже затем индивидуально вводить эту информацию в базу данных.



Хранимые функции



Хранимые функции

Хранимые функции (stored functions) аналогичны хранимым процедурам. Вместе они называются хранимыми подпрограммами. Они имеют ряд отличий, например, они отличаются по способу их вызова. Хранимые процедуры вызываются в операторе CALL, а хранимые функции могут являться аргументом оператора SQL. Ниже представлен пример определения функции, сопровождаемый примером обращения к этой функции.

CREATE FUNCTION PurchaseHistory (CustID)

    RETURNS CHAR VARYING (200)

    BEGIN

        DECLARE purch CHAR VARYING (200)

            DEFAULT '' ;

        FOR x AS SELECT *

                FROM transaction t

                WHERE t.customerID = CustID

        DO

            IF x.description <> ''

              THEN SET purch=purch ',' ;

            END IF ;

           SET purch=purch x.description ;

        END FOR

        RETURN purch ;

END ;

Функция, заданная подобным образом, сводит воедино описания всех покупок, произведенных клиентом с определенным идентификационным номером, выбранным из таблицы TRANSACTIONS. Следующая команда, содержащая вызов функции PurchaseHistory, заносит в таблицу информацию о всех покупках, сделанных клиентом с идентификационным номером 314259:

SET customerID=3142 59 ;

UPDATE customer

        SET history=PurchaseHistory (customerlD)

        WHERE customerID=314259 ;



Хранимые модули



Хранимые модули

Хранимые модули (stored modules) могут содержать множество подпрограмм, т.е. процедур и (или) функций SQL. Каждый пользователь с полномочиями на выполнение модуля имеет доступ ко всем подпрограммам этого модуля. Полномочия на выполнение отдельных подпрограмм модуля предоставляться не могут. Ниже приведен пример хранимого модуля.

CREATE MODULE mod1

        PROCEDURE MatchScore

                (IN white CHAR (20),

                IN black CHAR (20),

                IN result CHAR (3),

                OUT winner CHAR (5) )

        BEGIN ATOMIC

                CASE result

                        WHEN '1-0' THEN

                                SET winner = 'white' ;

                        WHEN '1-0' THEN

                                SET winner = 'black' ;

                        ELSE

                                SET winner = 'draw' ;




                        END CASE

                END ;

        FUNCTION PurchaseHistory (CustID)

        RETURNS CHAR VARYING (200)

        BEGIN

                         DECLARE purch CHAR VARYING (200)

                                        DEFAULT '' ;

                        FOR X AS SELECT *

                                                FROM transaction t

                                                WHERE t.cuStomerlD = CustID

                        DO

                                        IF x.description <> ''



                                                THEN SET purch = purch | | ' . ' ;

                                        END IF;

                                        SET purch = purch x.description ;

                        END FOR

                        RETURN purch ;

        END ;

END MODULE ;

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

 

Хранимые процедуры



Хранимые процедуры

Хранимые процедуры (stored procedures) находятся на сервере баз данных, а не на компьютере пользователя, как это было до появления SQL/PSM. Хранимая процедура должна быть определена, после чего ее можно вызвать с помощью команды CALL. Хранение процедуры на сервере уменьшает сетевой обмен и повышает производительность. Команда CALL является единственным сообщением, передаваемым от пользователя к серверу. Ниже приведен пример создания процедуры.

EXEC SQL

CREATE PROCEDURE MatchScore

        (IN white CHAR (20),

        IN black CHAR (20),

        IN result CHAR (3),

        OUT winner CHAR (5) )

   BEGIN ATOMIC

     CASE result

        WHEN '1-0' THEN

                SET winner='white' ;

        WHEN '0-1 ' THEN

                SET winner='black' ;

        ELSE

                SET winner='draw' ;

  END CASE END ;

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

CALL MatchScore ('Kasparov', 'Karpov', '1-0', winner);

Три первых аргумента являются входными параметрами, которые передаются процедуре MatchScore. Четвертый аргумент является выходным параметром, который процедура Match-Score использует для возврата своих результатов в вызывающую программу. В приведенном примере она возвращает значение 'white'.



IF...THEN...ELSE...END IF



IF...THEN...ELSE...END IF

Основной управляющей структурой является IF...THEN...ELSE...END IF. Если условие IF истинно, выполняются команды предложения THEN. В противном случае выполняются команды предложения ELSE. Например:

IF

vfname = 'Brandon'

THEN

    UPDATE students

        SET Fname = 'Brandon'

    WHERE StudentID = 314159 ;

ELSE

    DELETE FROM students

    WHERE StudentID = 314159 ;

END IF

В приведенном примере, если переменная vfname содержит значение 'Brandon', в списке студентов произойдет обновление записи с идентификатором 314159— в поле Fname будет помещено значение 'Brandon1. Если же переменная содержит какое-либо другое значение, отличное от Brandon', запись с идентификатором 314159 будет удалена из таблицы Students.

Выражение IF...THEN...ELSE...END IF больше всего подходит, если в зависимости от выполнения некоторого условия существуют два варианта дальнейшего поведения программы. Однако очень часто приходится иметь дело с большим количеством вариантов. В таких случаях следует использовать оператор CASE.



ITERATE



ITERATE

Оператор ITERATE позволяет изменять последовательность выполнения команд в циклах SQL. Циклы SQL представлены операторами LOOP, WHILE, REPEAT и FOR. Если условие в операторах циклов является истинным или не задано, тут же оператор ITERATE начинает следующую итерацию цикла. Если же условие итерации является ложным или неопределенным, цикл завершается и выполняются следующие за ним команды:

AsteroidPreload4:

SET vcount = 0 ;

WHILE

    vcount < 1000 DO

        SET vcount=vcount+l ;

        INSERT INTO asteroid (AsteroidID)

            VALUES (vcount) ;

        ITERATE AsteroidPreload4 ;

        SET vpreload = 'DONE' ;

END WHILE AsteroidPreload4

Оператор ITERATE все время передает управление в начало цикла WHILE, но до тех пор, пока переменная vcount не будет равна 9999. В следующей итерации переменная vcount увеличится до 10000, выполнится оператор INSERT, после чего оператор ITERATE прекратит итерации, переменная vpreload получит значение 'DONE', а выполнение перейдет к команде, следующей за циклом.



Курсоры



Курсоры

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

BEGIN

    DECLARE ipocandidate CHARACTER (30) ;

    DECLARE cursorl CURSOR FOR

            SELECT company

            FROM biotech ;

    OPEN cursor1 ;

    FETCH cursor1 INTO ipocandidate ;

    CLOSE cursor1;

END ;



LEAVE



LEAVE

Оператор LEAVE (покинуть) действует согласно названию. Как только выполнение программы доходит до оператора LEAVE с меткой, он передает управление команде, расположенной сразу после помеченной. Например:

AsteroidPreload:

SER vcount = 0 ;

LOOP

SET vcount = vcount+1 ;

    IF vcount > 1000

        THEN

            LEAVE AsteroidPreload;

    END IF ;

    INSERT INTO asteroid (AsteroidID)

        VALUES (vcount) ;

END LOOP AsteroidPreload

Приведенный выше код создает 1000 последовательно пронумерованных записей в таблице астероидов и затем завершает цикл.



LOOP...END LOOP



LOOP...END LOOP

Структура LOOP позволяет многократно выполнять некоторую последовательность команд SQL. После выполнения последней команды SQL, находящейся внутри структуры LOOP...ENDLOOP, цикл передает управление первой команде цикла, и все команды цикла выполняются еще раз. Синтаксис структуры LOOP...ENDLOOP имеет следующий вид:

LOOP

    SET vcount=vcount+1 ;

    INSERT INTO asteroid (AsteroidID)

        VALUES (vcount) ;

END LOOP

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

Необходимо отметить, что данный фрагмент кода имеет один существенный недостаток. Созданный им цикл является бесконечным. В нем нет кода окончания, следовательно, добавление в таблицу строк будет продолжаться до тех пор, пока СУБД будет располагать местом на диске. Затем система в лучшем случае сгенерирует исключение, а в худшем — просто аварийно завершит работу.

Для практического использования оператора LOOP необходимо иметь возможность выхода из цикла без возникновения исключения. Для этого имеется оператор LEAVE.



Необрабатываемые состояния



Необрабатываемые состояния

Предположим, в предыдущем примере возникнет состояние, при котором значение SQLSTATE будет отличным от '23000'. Ваш обработчик не может обработать подобное состояние. Так как в текущей процедуре такое состояние не предусмотрено, выполняется команда RESIGNAL. После этого состояние может быть обработано на более высоком уровне. Если же и на этом уровне состояние нельзя обработать, она передается на еще более высокий уровень и т.д., пока состояние не будет обработано или пока не будет сгенерирована ошибка в основном приложении. Основная идея вышесказанного заключается в следующем: если во время выполнения команды SQL возможно появление исключений, необходимо написать обработчики всех возможных исключений. Это позволит намного упростить отладку.



Объявление обработчиков состояний



Объявление обработчиков состояний

Обработчик состояния можно поместить в составную команду. При создании обработчика вначале следует объявить состояние, которое обработчик должен обрабатывать. Объявленное состояние может быть исключением или же некоторым другим состоянием. В табл. 19.2 представлены возможные состояния, а также кратко описаны причины возникновения состояния каждого вида.



Обработка состояний



Обработка состояний

Программу можно написать таким образом, чтобы значение параметра SQLSTATE контролировалось после выполнения каждой команды SQL. Итак, используем приобретенные знания на практике.

При получении сообщения кода класса '00' вряд ли необходимо предпринимать дополнительные действия. Продолжайте делать то, что вы планировали.

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

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



Оператор CASE с поиском



Оператор CASE с поиском

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

CASE

WHEN vmajor

        IN ('Computer Science', 'Electrical Engineering')

        THEN INSERT INTO geeks (StudentID, Fname, Lname)

            VALUES(:sid, :sfname, :slname) ;

    WHEN vclub

        IN ('Amateur Radio', 'Rocket1,'Computer')

        THEN INSERT INTO geeks (StudentID, Fname, Lname)

            VALUES(:sid, :sfname, :slname) ;

    ELSE

        INSERT INTO poets (StudentID, Fname, Lname)

            VALUES(:sid, :sfname, :slname) ;

    END CASE

Чтобы избежать возможности возникновения исключения, следует поместить всех студентов, которые не являются "физиками" (geeks), в таблицу poets ("лирики")- Конечно, не все "не физики" являются "лириками" — ведь есть же еще и "футболисты", не говоря уже о "химиках". Это не меняет сути дела, так как в оператор CASE всегда можно добавить еще несколько предложений WHEN.



Операторы управления ветвлением



Операторы управления ветвлением

Основным недостатком стандарта SQL-86, не позволяющим считать SQL полноценным процедурным языком, являлось отсутствие управляющих структур. До появления SQL/PSM строгую последовательность выполнения команд нельзя было нарушить без использования базового языка, такого как С или Basic. SQL/PSM получил в свое распоряжение аналогичные управляющие структуры, позволяя тем самым решать многие задачи без привлечения других языков программирования.



Переменные



Переменные

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

BEGIN

DECLARE prezpay NUMERIC ;

    SELECT salary

    INTO prezpay

    FROM EMPLOYEE

    WHERE jobtitle= 'president' ;

END ;



Полномочия



Полномочия

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

На удаление записи из таблицы.

На вставку записи в таблицу.

На обновления записи в таблице.

На создание ссылок на поля таблицы.

На использование домена.

SQL/PSM добавляет к уже существующим еще один вид полномочий — полномочия на выполнение. Ниже приведены два примера.

GRANT EXECUTE on MatchScore to TournamentDirector ;

GRANT EXECUTE on PurchaseHistory to SalesManager ;

Эти команды предоставляют возможность руководителю шахматного турнира вызывать процедуру MatchScore, а менеджеру по продажам компании — вызывать функцию Purchase-History. Пользователи, которые не имеют полномочий на выполнение подпрограммы, не могут ее использовать.



Присваивание



Присваивание

С появлением SQL/PSM SQL наконец-то получил возможность, которую всегда имели даже самые примитивные процедурные языки, — возможность присваивания значения переменной. Присваивание выглядит так:

SET переменная = значение ;

где переменная — имя переменной, а значение — выражение. Ниже приведено несколько примеров присваивания.

SET vfname = 'Brandon' ;

SET varea = 3.1416 * :radius * :radius ;

SET vhiggsmass = NULL ;



Простой оператор CASE



Простой оператор CASE

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

CASE vinajor

WHEN 'Computer Science'

    THEN INSERT INTO geeks (StudentID, Fname, Lname)

            VALUES(:sid, :sfname, :slname) ;

    WHEN 'Sports Medicine'

    THEN INSERT INTO jocks (StudentID, Fname, Lname)

            VALUES(:sid, rsfname, :slname) ;

    ELSE INSERT INTO undeclared (StudentID, Fname, Lname)

            VALUES(:sid, :sfname, :slname) ;

    END CASE

Команды предложения ELSE выполняются, если vmajor неТгопадает ни в одну из категорий, заданных предложениями THEN.



REPEAT...UNTIL..END REPEAT



REPEAT...UNTIL..END REPEAT

Цикл REPEAT очень похож на цикл WHILE. Различие между ними заключается в том, что условие проверяется после выполнения команд цикла. Например:

AsteroidPreload3 :

SET vcount = 0 ;

REPEAT

SET vcount = vcount+1 ;

    INSERT INTO asteroid (AsteroidID)

        VALUES (vcount) ;

    UNTIL vcount = 1000

END REPEAT AsteroidPreload3

Совет 1


Совет 1

Хотя во всех трех приведенных выше примерах одна и та же операция с одинаковой легкостью выполнялась тремя различными методами (с помощью операторов LOOP, WHILE и REPEAT), очень часто встречаются ситуации, когда один из методов имеет явные преимущества перед другими. Поэтому лучше хорошо знать все три метода и в конкретных обстоятельствах выбрать наиболее подходящий.



Составные команды



Составные команды

В этой книге SQL рассматривается как непроцедурный язык, который применяется в основном для обработки наборов данных, а не отдельных записей. В то же время в этой главе вы узнаете, что это положение постепенно меняется. SQL становится процедурным языком, в основных чертах все еще оставаясь средством для обработки наборов данных. Версия SQL, определяемая стандартом SQL-92, не соответствовала процедурной модели, в которой команды выполняются одна за другой в определенной последовательности. Команды SQL были одиночными и, как правило, встроенными в код программы C++ или Visual Basic. Фактически с помощью ранних версий SQL пользователи не могли создать запрос или выполнить некоторые другие операции с помощью последовательности операторов SQL. Выполнение же последовательности команд SQL вызывало значительное снижение производительности. Каждая выполняющаяся команда SQL должна послать сообщение с места работы пользователя на сервер баз данных, а тот должен отослать ответ в обратном направлении. Это увеличивает сетевой обмен и тем самым приводит к дополнительной нагрузке на сеть.

SQL: 1999 и SQL:2003 предоставляют возможность создания составных команд, образованных отдельными командами SQL, выполняемыми в один прием. Использование составных команд позволяет снизить загрузку сети, поскольку все отдельные команды, образующие составную, вместе пересылаются на сервер, возвращающий обратно один ответ.

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

void main {

EXEC SQL

BEGIN

 INSERT INTO students (StudentID, Fname, Lname)

    VALUES (:sid, :sfname, :sid) ;

 INSERT INTO roster (ClassID, Class, StudentID)

    VALUES (:cid, rename, :sid) ;

 INSERT INTO receivable (StudentID, Class, Fee)

    VALUES (:sid, :cname, :cfee) ;

        END ;

/* Проверка значения SQLSTATE на код ошибки */

}

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



Состояния



Состояния

Все знают, что означает, когда о человеке говорят, что он дошел до "кондиции". Его состояние наутро после этого может быть тяжелым, очень тяжелым, или же все обойдется. Так и в SQL. Результат выполнения команды SQL может быть успешным, сомнительным или неправильным. Каждый из таких результатов является "состоянием" (condition).

Каждый раз, когда выполняется команда SQL, сервер базы данных обновляет значение параметра статуса SQLSTATE. Он представляет собой поле из пяти символов. Значение SQLSTATE содержит информацию об успешном или неудачном завершении команды. В случае возникновения ошибки значение содержит ее код.

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



Значения класса sqlstate



Таблица 19.1. Значения класса sqlstate

Класс Описание
00 Успешное завершение
01 Предупреждение
02 Не найден
Другое Сгенерировано исключение

Значение класса '00' означает, что предыдущая команда SQL выполнена успешно. В большинстве случаев это наиболее желаемый результат.

Значение класса '01' означает предупреждение. Предупреждение указывает на то, что в ходе выполнения команды SQL случилось что-то незапланированное. В данном случае СУБД не "знает", произошла ошибка или нет. Предупреждение обращает внимание разработчика на то, что требуется тщательно проверить команду SQL.

Значение класса '02' означает, что не получено никаких данных в результате выполнения команды SQL. Это может быть хорошим или плохим известием, в зависимости от обстоятельств. Иногда результат в виде пустой таблицы — как раз то, что требуется разработчику.

Любой код, отличный от значений '00', '0Г или '02', указывает на наличие ошибки в программе. Три последних символа параметра SQLSTATE содержат код ошибки. Два символа кода класса и три символа кода ошибки вместе составляют пять символов значения SQLSTATE.



Состояния, которые можно определить в обработчике



Таблица 19.2. Состояния, которые можно определить в обработчике

Состояние Описание
SQLSTATE VALUE ' xxyyy ' Соответствующее значение sqlstate
SQLEXCEPTION Класс sqlstate, отличный от '00', ' 01' или '02'
SQLWARNING Класс ' 01'
NOT FOUND Класс ' 02'

Ниже приведен пример объявления состояния.

BEGIN

DECLARE constraint_violation CONDITION

        FOR SQLSTATE VALUE '23 000' ;

END ;

Приведенный пример не является взятым из жизни, поскольку внутри структуры BEGIN...END должны располагаться и команда SQL, ответственная за возникновение особого состояния, и его обработчик.



Сложные команды, атомарность, курсоры, переменные



В этой главе...

Сложные команды, атомарность, курсоры, переменные и состояния
Управляющие структуры
Создание циклов
Использование хранимых процедур и функций
Предоставление полномочий на выполнение
Создание и использование хранимых модулей
В течение многих лет ведущие специалисты в области технологий баз данных работали над разработкой стандартов. После выхода очередного стандарта и начала его применения пользователями и программистами во всем мире сразу начинается процесс разработки следующего. Так было и в случае SQL-92. Семь лет разделяет выпуск SQL-92 и выход первого компонента SQL: 1999. Однако все эти годы продолжалась кипучая деятельность, в результате которой ANSI и ISO выпустили дополнение к SQL-92, названное SQL-92/PSM (Persistent Stored Modules — постоянно хранимые модули). Это дополнение послужило основой для одного из разделов стандарта SQL: 1999 с тем же названием. SQL/PSM как часть SQL:2003 определяет набор операторов, предоставляющих SQL возможности по созданию управляющих структур, обычных для наиболее мощных языков программирования. Благодаря этому стало возможным решать многие задачи только с использованием SQL, без привлечения других программных средств. Предыдущие версии SQL требовали непрерывного переключения между SQL и процедурным базовым языком.

Оператор ELSE является необязательным. Однако,



Внимание

Оператор ELSE является необязательным. Однако, если он отсутствует и выражение CASE не соответствует ни одному предложению THEN, SQL генерирует исключение.

WHILE...DO...END WHILE



WHILE...DO...END WHILE

Оператор WHILE предоставляет другой метод многократного выполнения последовательности команд SQL. Если условие оператора WHILE истинно, цикл продолжает выполняться. Если нет — выполнение цикла тут же прекращается. Например:

AsteroidPreload2 :

SET vcount = 0 ;

WHILE

    vcount < 100 0 DO

        SET vcount = vcount+1 ;

        INSERT INTO asteroid (AsteroidID)

            VALUES (vcount) ;

END WHILE AsteroidPreload2

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