Мартин Грубер - Понимание SQL (991940), страница 48
Текст из файла (страница 48)
Этого требуетсинтаксис команды FETCH. UPDATE работает так же.Вы можете увеличить значение комиссионных всем продавцам, которые имеютзаказчиков с оценкой=300, следующим способом. Сначала вы обьявляете курсор:EXEC SOL DECLARE CURSOR High_Cust ASSELECT *FROM SalespeopleWHERE snum IN (SELECT snumFROM CustomersWHERE rating = 300);Затем вы выполняете модификации в цикле:EXEC SQL OPEN CURSOR High_cust;while SQLCODE = 0 dobeginEXEC SOL FETCH High_custINTO :id_num, :salesperson, :loc, :comm;EXEC SQL UPDATE SalespeopleSET comm = comm + .01WHERE CURRENT OF High_cust;end;EXEC SQL CLOSE CURSOR High_cust;Обратите внимание: что некоторые реализации требуют, чтобы вы указывали вопределении курсора, что курсор будет использоваться для выполнения командыUPDATE на определенных столбцах. Это делается с помощью заключительной фразыопределения курсора — FOR UPDATE <column list>.
Чтобы обьявить курсор High_custтаким способом, так чтобы вы могли модифицировать командой UPDATE столбецcomm, вы должны ввести следующее предложение:EXEC SQL DECLARE CURSOR High_Cust ASSELECT *FROM SalespeopleWHERE snum IN (SELECT snumFROM CustomersWHERE rating = 300)FOR UPDATE OF comm;Это обеспечит вас определенной защитой от случайных модификаций, которыемогут разрушить весь порядок в базе данных.ПЕРЕМЕННАЯ INDICATORПустые (NULLS) значения — это специальные маркеры определяемые самойSQL.
Они не могут помещаться в главные переменные. Попытка вставить NULL значения в главнуюпеременную будет некорректна, так как главные языки не поддерживают NULL значений в SQL, по определению. Хотя результат при попытке вставитьNULL значение в главную переменную определяет проектировщик, этот результат недолжен ротиворечить теории базы данных, и поэтому обязан произвести ошибку: кодSQLCODE в виде отрицательного числа, и вызвать подпрограмму управления ошибкой.
Естеcтвенно вам нужно этого избежать. Поэтому, вы можете выбрать NULL значения с допустимыми значениями, не приводящими к разрушению вашей программы.Даже если программа и не разрушится, значения в главных переменных станут неправильными, потому что они не могут иметь NULL значений. Альтернативным методом предоставляемым для этой ситуацией является — функция переменной indicator(указатель).Переменная indicator — обьявленная в разделе объявлений SQL напоминаетдругие переменные. Она может иметь тип главного языка который соответствует числовому типу в SQL.
Всякий раз, когда вы выполняете операцию, которая должна поместить NULL значение в переменную главного языка, вы должны использоватьпеременную indicator, для надежности. Вы помещаете переменную indicator в командуSQL непосредственно после переменной главного языка которую вы хотите защитить,без каких-либо пробелов или запятых, хотя вы и можете, при желании, вставить словоINDICATOR.Переменной indicator в команде, изначально присваивается значение 0. Однако,если производится значение NULL, переменная indicator становится равной отрицательному числу. Вы можете проверить значение переменной indicator, чтобы узнать,было ли найдено значение NULL.
Давайте предположим, что поля city и comm, таблицы Продавцов, не имеют ограничения NOT NULL, и что мы объявили вразделе обьявлений SQL, две ПАСКАЛЬевские переменные целого типа, i_a и i_b.(Нет ничего такого в разделе обьявлений, что могло бы представить их как переменные indicator. Они станут переменными indicator, когда будут использоваться какпеременные indicator.)Имеется одна возможность:EXEC SQL OPEN CURSOR High_cust;while SQLCODE = O dobeginEXEC SQL FETCH High_custINTO :id_num, :salesperson, :loc, :i_a, :commINDlCATOR, :i_b;If i_a >= 0 and i_b >= 0then {no NULLs produced}beginEXEC SQL UPDATE SalespeopleSET comm = comm + .01WHERE CURRENT OF Hlgh_custend {then}else {one or both NULL}beginIf i_a < 0 then writeln('salesperson ', id_num,' has no city');If i_b < 0 then writeln('salesperson ', id_num,' has no commission')end {else}end; {while}EXEC SQL CLOSE CURSOR High_cust;Как вы видите, мы включили, ключевое слово INDICATOR в одном случае, и исключили его в другом случае, чтобы показать, что эффект будет одинаковым в любомслучае.
Каждая строка будет выбрана, но команда UPDATE выполнится только еслиNULL значения не будут обнаружены.Если будут обнаружены NULL значения, выполнится еще одна часть программы,которая распечатает предупреждающее сообщение, где было найдено каждое NULLзначение.Обратите внимание: переменные indicator должны проверяться в главном языке,как указывалось выше, а не в предложении WHERE команды SQL.Последнее в принципе не запрещено, но результат часто бывает непредвиденным.ИСПОЛЬЗОВАНИЕ ПЕРЕМЕННОЙ INDICATOR ДЛЯЭМУЛЯЦИИ NULL ЗНАЧЕНИЙ SQLДругая возможность состоит в том, чтобы обрабатывать переменную indicator,связывая ее с каждой переменной главного языка специальным способом, эмулирующим поведение NULL значений SQL.Всякий раз, когда вы используете одно из этих значений в вашей программе, например в предложении if ...
then, вы можете сначала проверить связанную переменную indicator, является ли ее значение=NULL. Если это так, то вы обрабатываетепеременную по-другому. Например, если NULL значение было извлечено из поля cityдля главной переменной city, которая связана с переменной indicator — i_city, выдолжны установить значение city равное последовательности пробелов. Это будетнеобходимо, только если вы будете распечатывать его на принтере; его значение недолжно отличаться от логики вашей программы. Естественно, i_city автоматически установливается в отрицательное значение.
Предположим, что вы имели следующуюконструкцию в вашей программе:If sity = 'London' then comm: = comm + .01else comm: = comm - .01Любое значение, вводимое в переменную city, или будет равно "London", или небудет равно. Следовательно, в каждом случае значение комиссионных будет либоувеличено, либо уменьшено. Однако, эквивалентные команды в SQL выполняются поразному:EXEC SQL UPDATE SalespeopleSET comm = comm + .01WHERE sity = 'London';иEXEC SQL UPDATE SalespeopleSET comm = comm - .01;WHERE sity <> 'London';(Вариант на ПАСКАЛе работает только с единственным значением, в то времякак вариант на SQL работает со всеми таблицами.)Если значение city в варианте на SQL будет равно значению NULL, оба предиката будут неизвестны, и значение comm, следовательно, не будет изменено в любомслучае.Вы можете использовать переменную indicator, чтобы сделать поведение вашегоглавного языка непротиворечащим этому, с помощью создания условия, которое исключает NULL значения:If i_city > = O thenbeginIf city = 'London' then comm: = comm + .01else comm: = comm - .01;end;{begin and end нужны здесь только для понимания}ПРИМЕЧАНИЕ: Последняя строка этого примера содержит ремарку — {begin иend необходимы только для понимания}В более сложной программе, вы можете захотеть установить Булеву переменную в "верно", чтобы указать что значение city = NULL.
Затем вы можете просто проверять эту переменную всякий раз, когда вам это необходимо.ДРУГОЕ ИСПОЛЬЗОВАНИЕ ПЕРЕМЕННОЙ INDICATORПеременная indicator также может использоваться для назначения значенияNULL. Просто добавьте ее к имени главной переменной в команде UPDATE илиINSERT тем же способом что и в команде SELECT. Если переменная indicator имеетотрицательное значение, значение NULL будет помещено в поле. Например, следующая команда помещает значения NULL в поля city и comm, таблицы Продавцов,всякий раз, когда переменные indicator — i_a или i_b будут отрицательными; в противном случае она помещает туда значения главных переменных:EXEC SQL INSERT INTO SalespeopleVALUES (:Id_num, :salesperson, :loc:i_a, :comm:i_b);Переменная indicator используется также, чтобы показывать отбрасываемуюстроку.
Это произойдет если вы вставляете значения символов SQL в главную переменную которая не достаточно длинна чтобы вместить все символы. Это особая проблема с нестандартным типами данных — VARCHAR и LONG (смотри Приложение C).В этом случае, переменная будет заполнена первыми символами строки, а последниесимволы будут потеряны. Если используется переменная indicator, она будет установлена в положительное значение, указывающее на длину отбрасываемой части строки,позволяя таким образом вам узнать, сколько символов было потеряно.В этом случае, Вы можете проверить с помощью просмотра — значение переменной indicator > 0, или < 0.РЕЗЮМЕКоманды SQL вкладываются в процедурные языках, чтобы объединить силыдвух подходов.
Некоторые дополнительные средства SQL необходимы, чтобы выполнить эту работу. Вложенные команды SQL транслируемые программой, называемойпрекомпилятором, в форму пригодную для использования транслятором главногоязыка, и используемые в этом главном языке, как вызовы процедуры к подпрограммам которые создает прекомпилятор, называются — модулями доступа. ANSI поддерживает вложение SQL в языки: ПАСКАЛЬ, ФОРТРАН, КОБОЛ, и PL/I. Другие языкитакже используются, особенно Си. В попытке кратко описать вложенный SQL, имеются наиболее важные места в этой главе:* Все вложенные команды SQL начинаются словами EXEC SQL и заканчиваютсяспособом, который зависит от используемого главного языка.* Все главные переменные, доступные в командах SQL, должны быть обьявленыв разделе объявлений SQL прежде, чем они будут использованы.* Всем главным переменным должно предшествовать двоеточие, когда они используются в команде SQL.* Запросы могут сохранять свой вывод непосредственно в главных переменных,используя предложение INTO, если и только если, они выбирают единственную строку.* Курсоры могут использоваться для сохранения вывода запроса, и доступа кодной строке в каждый момент времени.