Материал: Graber_Martin_-_SQL_dlya_prostykh_smertnykh_-_2014

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Глава 25. Использование SQL с другими языками программирования

FROM Customers WHERE rating = 300);

Затем можно вести обновления в цикле:

ЕХЕС SQL OPEN CURSOR High_cust; while SQLCODE = О do

begin

ЕХЕС SQL FЕТСН High_cust

INTO :id_num, :salesperson, :loc, :comm; ЕХЕС SQL UPDATE Salespeople

SET comm = comm + .01 WHERE CURRENT OF High_cust;

end;

ЕХЕС SQL CLOSE CURSOR High_cust;

Замечание: некоторые программные продукты требуют, чтобы в определении кур­ сора было указано, что он будет использоваться для выполнения команд UPDATE для определенных столбцов. Это делается добавлением в определение курсора FOR UPDATE OF <список столбцов>. Чтобы определить курсор High_cust для выполне­ ния обновления значений столбца comm, нужно ввести следующее предложение:

ЕХЕС SQL DECLARE CURSOR High_Cust AS SELECT *

FROM Salespeople WHERE snum IN

(SELECT snum

FROM Customers WHERE rating = 300)

FOR UPDATE OF comm;

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

привести к весьма тяжелым последствиям.

Индикаторы переменных

NULL - это специальные маркеры, определенные в SQL. Ил нельзя использовать

в переменных включающего языка. Попытка вставить NULL в переменную включаю­

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

NULL-значений, определенных в SQL. Хотя результат попытки вставить NULL-

значения во включающий язык зависит от конкретной реализации, результат, опреде­

ленный в теории баз данных, создает ошибочную ситуацию: SQLCODE получает от­ рицательное числовое значение, и может быть вызвана программа обработки

292

Индикаторы переменных

ошибочных ситуаций. Обычная реакция - попытка избежать этого. Часто можно вы­ бирать NULL-значения наряду со реальными, чтобы избежать аварийного завершения программы. Если программа не завершается автоматически, значения в переменных включающего языка будут некорректны, поскольку в них нет NULL-значений. Альтер­ нативный метод обработки этой ситуации заключается в использовании индикаторов

переменных.

Индикаторы переменных, как и остальные переменные, объявляются в разделе объявления переменных SQL. Они имеют тип, определенный во включающем языке и соответствующий числовому (numeric) типу SQL. Как только выполняется операция, которая может поместить NULL-значения в переменные вызывающего языка, можно

использовать индикатор переменной в качестве меры предосторожности. Индикатор

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

Перед выполнением команды индикатору переменной присваивается начальное зна­

чение О. Еслн в процессе выполнения команды переменная получает NULL-значение, то индикатор переменной приобретает отрицательное значение. После выполнения коман­ ды можно проверить значение индикатора переменной и определить, было ли обнару­ жено NULL-значение. Предположим, поля city и comm таблицы Salespeople не имеют ограничения NOT NULL, и в разделе объявления переменных SQL объявлены две пере­ менные языка Pasca\ типа integer, i_a и i_b. (В разделе объявления переменных ничто не говорит о том, что эти переменные будут применяться как индикаторы переменных. Они становятся индикаторами, когда их используют в своем собственном смысле.) Пе­

ред вами одна из возможностей:

ЕХЕС SQL OPEN CURSOR High_cust; while SOLCODE = О do

begiп

ЕХЕС SQL FЕТСН High_cust

INTO :id_пum, :salespersoп,

:loc:i_a, :commINDICATOR:i_b; if i_a >= О апd i_b >= О theп

{ПО NULLS produced} ЕХЕС SQL UPDATE Salespeople

SET comm = comm + .01 WHERE CURRENT OF High_cust;

Else

{опе ОГ both NULL}

begiп

if i_a < О theп

writelп ('salespersoп · ,id_пum, · has по city');

if i_b < О theп

293

Глава 25. Использование SQL с другими языками программирования

writeln ( ·salesperson ·, id_num, · has по commissions ·);

end;

{else} end; {while}

ЕХЕС SQL CLOSE CURSOR High_cust;

Из примера ясно, что в одном случае включено ключевое слово INDICATOR, во втором случае оно не использовалось с целью иллюстрации этих возможностей; по действию индикаторов переменных эти два варианта ничем не отличаются. Извлека­ ется каждая строка, но команда UPDATE выполняется в том случае, если не обнаруже­

но NULL-значение. Если получено NULL-значение, то выполняется else - часть

программы, которая печатает предупреждающее сообщение, определяющее, где кон­ кретно было обнаружено NULL-значение. Замечание: индикаторы должны проверять­ ся во включающем языке, как в рассмотренном примере, а не в предложении WHERE команды SQL, что в общем-то законно, но может привести к непредсказуемым резуль­

татам.

Использование индикатора переменных для эмуляции NULL-значений

Можно трактовать индикаторы переменных, связанные с каждой переменной включающего языка как способ эмуляции NULL-значений SQL. Поскольку одно из этих значений используется в программе, например, в предложении if ". then, можно контролировать соответствующий индикатор переменной, чтобы увидеть, принимает ли она значение NULL. В этом случае возникает возможность различной трактовки переменных. Например, если NULL-значение было найдено в поле city для значения переменной включающего языка city, которая связана с индикатором _переменной i_ city, можно установить значение переменной city равным последовательности пробе­ лов, что необходимо, когда предполагается печатать это значение; оно не имеет значе­ ния для логики конкретной программы. Конечно, i_city автоматически принимает

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

if ". then:

if city = 'London' then

comm := comm + .01 else comm := comm - .01;

Любое значение, введенное в переменную city, будет либо равно значению 'London', либо не равно ему. Следовательно, комиссионные в любом случае либо уве­ личиваются, либо уменьшаются. Но в SQL эквивалентная команда работает по­

друrому:

ЕХЕС SOL UPDATE Salespeople SЕТ comm = comm + .01 WHERE city = 'London';

294

Индикаторы переменных

и

ЕХЕС SQL UPDATE Salespeople SЕТ comm = comm - .01; WHERE city <> 'London';

(Версия Pascal работает только с единственным значением, тогда как версия SQL действует на целой таблице.) Если значение city в версии SQL было равно NULL, то оба предиката принимают значение unknown (неизвестно) и, следовательно, значение comm не изменяется в обоих случаях. Во включающем языке можно добиться того же, используя индикатор переменной и задав условие, исключающее NULL-значения:

if i_city >= О then

begin

if city = 'London· then comm := comm + .01

else comm := comm - .01;

end;

{ begin и end необходимы в данном случае для большей наглядности }

В более сложной программе можно присвоить булевым переменным значение "ис­ тина", чтобы определить ситуацию, когда city имеет значение NULL. Затем можно просто проверить это значение переменной.

Другие пользователи индикатора переменных

Индикатор переменной можно использовать для назначения NULL-значений. Доба­

вить их к именам переменных включающего языка в команде UPDATE или INSERT, как в команде SELECT. Если индикатор переменной имеет отрицательное значение, то в

поле следует поместить NULL-значение. Например, следующая команда поместит

NULL-значение в поле city и в поле comm таблицы Salesperson, если индикаторы пере­ менных i_a или i_b имеют отрицательное значение; в противном случае они получат

значения переменных включающего языка:

ЕХЕС SQL INSERT INTO Salespeople

VALUES (:id_num, :salesperson, :loc:i_a, :comm:i_b);

Индикаторы переменных используются и для определения усечения строк, когда

символьное значение SQL вносится в переменную включающего языка, длина которой недостаточна для сохранения всех символов. Это специальная проблема для нестан­ дартных типов данных VARCHAR и LONG (см. приложение С). В этом случае в пере­

менную заносятся начальные символы строки, а те символы, которые не умещаются в

переменной, просто усекаются и теряются. При использовании индикатора переменной

он принимает положительное числовое значение, определяющее длину строки до ее

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

295

Глава 25. Использование SQL с другими языками программирования

для выяснения рассматриваемой здесь ситуации нужно выполнить проверку индикатора

переменной на > О, а не на < О.

Итоги

SQL-команды включаются в процедурные языки программирования для комбиниро­ вания сил двух подходов. Реализации такой возможности требует некоторых расширений SQL. Команды встроенного SQL транслируются с помощью программы, названной пред­ компилятором (препроцессором), для создания программы, понятной компилятору языка высокого уровня. Команды встроенного SQL заменяются вызовом подпрограмм, которые

создаются с помощью встроенного препроцессора; эти подпрограммы называются моду­

лями доступа. С помощью такого подхода ANSI поддерживает встроенный SQL для язы­ ков программирования Pascal, FORTRAN, COBOL, PL/1. Другие языки также используются разработчиками. Наиболее важным из них является С.

При описании встроенного SQL следует обратить особое внимание на следующее:

• Все встроенные команды SQL начинаются словами ЕХЕС SQL и заканчивают­

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

•Все переменные языка высокого уровня, используемые в командах SQL, долж­ ны быть внесены в раздел описаний SQL до своего применения.

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

•Выходные данные для запросов могут храниться непосредственно в перемен­ ных языка высокого уровня с помощью INTO тогда и только тогда, когда за­ прос выбирает единственную строку.

•Курсоры могут применяться для хранения выходных данных запроса и для дос­ тупа к ним по одной строке за один цикл обработки. Курсоры объявляются

(вместе с определением запроса, выходные данные которого содержит курсор), открываются (что соответствует выполнению запроса) и закрываются (что со­

ответствует удалению выходных данных из курсора, разрыву связи между вы­

ходными данными и курсором). Пока курсор открыт, можно использовать команду FETCH для доступа к выходным данным запроса: по одной строке для

каждого выполнения команды FETCH.

• Курсоры могут быть обновляемыми или "только для чтения". Чтобы быть об­

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

ление. Он не должен использовать предложения ORDER ВУ и UNION, которые запрещено применять в представлении. Необновляемый курсор является курсо­ ром "только для чтения".

296

Источник: https://studfile.net/preview/16418473/