|
|
Пакеты
и язык управления заданиями
Язык Transact-SQL позволяет сгруппировать последовательность операторов в один пакет, который может выполняться либо интерактивно, либо как файл операционной системы. Пользователь может также использовать конструкции языка управления заданиями, имеющиеся в Transact-SQL, для построения программ из отдельных операторов. В этой главе рассматриваются следующие темы: · дается общий обзор пакетов и языка управления заданиями; · приводятся правила для построения пакетов; · показывается, как использовать язык управления заданиями. До сих пор в данном руководстве рассматривались примеры, в которых выполнялся лишь один оператор. Пользователь задавал отдельные операторы, которые непосредственно выполнялись SQL Сервером с последующей выдачей результатов (интерактивный режим). Но SQL Сервер может выполнить по очереди сразу несколько операторов, объединенных в пакет (программу), как в интерактивном режиме, так и в пакетном режиме, когда задание хранится в виде файла. Пакет (набор) SQL операторов заканчивается специальной
командой, которая сообщает SQL Серверу о необходимости выполнения всех операторов в пакете.
Такой командой в специальной утилите SQL Сервера isql является команда “go” (выполнить), которая указывается в отдельной строке. Более
детально утилиты рассматриваются в справочном
руководстве по утилитам SQL Сервера. Вообще говоря, пакет может состоять из одного оператора, но обычно в пакет объединяются несколько операторов. Очень часто пакет хранится как файл операционной системы и затем вызывается на исполнение утилитой isql. В языке Transact-SQL предусмотрены специальные ключевые слова, которые собственно и образуют язык управления заданиями и которые позволяют пользователю влиять на последовательность выполнения операторов. Команды языка управления можно использовать как в отдельных операторах, так и в пакетах, а также в сохраненных процедурах и триггерах. Без команд управления отдельные SQL операторы выполняется последовательно в порядке их поступления. Исключение здесь составляют коррелированные запросы, которые обсуждались в главе 5 “Подзапросы: использование запросов внутри других запросов”. Команды управления позволяют изменять последовательность выполнения операторов в зависимости от получаемых результатов с помощью конструкций, используемых в языках программирования. Такие конструкции, как if…else, предназначенная для ветвления по условию, и while, предназначенная для циклического выполнения, позволяют управлять последовательностью выполнения SQL операторов. Язык управления заданиями, включенный в Transact-SQL, по существу, превращает стандартный SQL в язык программирования очень высокого уровня. В пакет можно включать только определенные SQL операторы. При составлении пакетов следует придерживаться следующих правил: · Следующие команды нельзя включать в пакет вместе с другими операторами: creat procedure (создать процедуру), creat rule (создать правило), creat default (создать значение по умолчанию), creat trigger (создать триггер), creat view (создать вьювер); · Следующие команды можно включать в пакет: creat database (можно создать базу данных, но из того же пакета нельзя обращаться к ее объектам), creat table (создать таблицу), creat index (создать индекс); · Правила и умолчания можно связывать со столбцами, но нельзя сразу использовать в одном и том же пакете. Например, вызов процедур sp_bindrule (присоединить правило) и sp_bindefault (присоединить значение по умолчанию) нельзя располагать в одном пакете с оператором insert, который использует эти правила и умолчания; · Команда use (использовать базу данных) должна содержаться в пакете, который выполняется перед пакетом, в котором располагаются операторы, обращающиеся к объектам этой базы; · Нельзя выполнить команду drop (удалить), а затем вновь создать тот же объект в этом же пакете; · Все опции, установленные в пакете с помощью команды set (установить), начинают действовать только после окончания выполнения этого пакета. Можно включить команду set и запросы к таблицам в один пакет, но опции, установленные этой командой, не будут действовать во время выполнения этих запросов. В этом разделе приводятся примеры, иллюстрирующие использование пакетов с утилитой isql, которая имеет специальную команду “go” для запуска пакета на исполнение. В следующий пакет включены два оператора выбора: select
count(*) from titles select
count(*) from authors go --------------------- 18 ---------------------- 23 (Выбрана 1
строка) Можно в одном пакете создать таблицу и сразу обратиться к ней. В следующем примере пакета создается таблица, затем в нее вставляется строка, после чего эта строка выбирается из таблицы: create table
test (column1 char(10), column2 int) insert test values ("hello", 598) select * from
test go (Выбрана 1
строка) column1 column2 -------- --------- hello 598 (Выбрана 1
строка) Команда creat view (создать вьювер) должна быть единственной командой в пакете. В следующем пакете, состоящем из одного оператора, создается вьювер: creat view
testview as select column1 from test go Команду use можно включать в пакет вместе с другими операторами, если эти операторы обращаются к базе данных, которая была текущей перед вызовом пакета. В следующем примере происходит выборка из таблицы базы данных master, а затем открывается база данных pubs2. Здесь предполагается, что база данных master была текущей перед вызовом пакета. После выполнения этого пакета текущей становится база данных pubs2. select
count(*) from sysdatabase use pubs2 go ------------------ 9 (Выбрана 1
строка) Команду drop (удалить объект) можно включать в пакет вместе с другими операторами, если в том же пакете уже не нужно будет обращаться к удаляемому объекту или вновь создавать его. В следующем примере показан пакет, состоящий из оператора drop и оператора select: drop table
test select
count(*) from titles go ---------------------- 18 (Выбрана 1
строка) Если в пакете где-нибудь имеется синтаксическая ошибка, то в нем не будет выполнен ни один оператор. Например, в следующем пакете имеется опечатка в последнем операторе, поэтому в результате появляется сообщение об ошибке: select
count(*) from titles select
count(*) from authors slect count(*)
from publishers go Msg 156, Level 15, State 1: SQL Server 'MAGOO', LIne 3: Incorrect syntax near the keyword 'count'. (Неправильная команда около слова ‘count’). Пакеты, в которых нарушены правила их составления, также вызывают сообщение об ошибке. Далее приводятся примеры неправильных пакетов: create table
test (column1 char(10), column2 int) insert test values ("hello", 598) select * from
test create view
testview as select column1 from test go Msg 111, Level 15, State 3: Server 'hq', Line 6: CREATE VIEW must be the first command in a query batch. (Команда создания вьювера должна
быть первой в пакете.) create view
testview as select column1 from test insert
testview values ("goodbye") go Msg 127, Level 15, State 1: Server 'hq', Procedure 'testview', Line 3: This CREATE may only contain 1 statement. (Команда создания вьювера должна
быть единственной в пакете.) Следующий пакет будет работать только в том случае, если текущей базой данных будет база данных, указанная в операторе use. Если же он будет запущен из другой базы данных, например master, то будет выдано сообщение об ошибке. use pubs2 select * from
titles go Msg 208, Level 16, State 1: Server 'hq', Line 2: Invalid object name 'titles'. (Неправильный объект 'titles'.) drop table
test create table
test (column1
char(10), column2 int) go Msg 2714, Level 16, State 1: Server 'hq', Line 2: There is already an object named 'test' in the
database.
(В базе данных уже имеется объект
с названием 'test'.) Пакет можно сохранить в виде файла операционной системы, а затем вызвать его на исполнение утилитой isql. Файл может содержать несколько пакетов, каждый из которых заканчивается ключевым словом “go”. Например, следующий файл содержит три пакета: use pubs2 go select
count(*) from titles select
count(*) from authors go create table
test (column1 char(10), column2 int) insert test values ("hello", 598) select * from
test go При выполнении этого файла утилитой isql получаются следующие результаты: -------------
18 (Выбрана 1
строка) -------------
23 (Выбрана 1
строка) (Выбрана 1
строка) column1 column2 --------- --------- hello 598 (выбрана 1
строка) В справочном руководстве по утилитам SQL Сервера в разделе об утилите isql приводится информация о зависимости выполнения пакетных файлов от операционного окружения (среды). Команды языка управления заданиями можно использовать как в интерактивном режиме, так и в пакетном, а также в сохраненных процедурах. Ключевые слова языка управления заданиями и их значение приведены в следующей таблице: Таблица 13-1: Ключевые слова языка управления заданиями
Условный оператор if…else
Ключевое слово if (если), независимо от своего дополнения else (иначе), служит для указания условия, которое определяет нужно ли выполнять следующий оператор. Следующий оператор выполняется, если это условие истинно, т.е. если его значение равно TRUE (истина). Ключевое слово else служит для указания альтернативного SQL оператора, который выполняется, если условие, указанное в конструкции if оказалось ложным (FALSE). Условный оператор имеет следующий синтаксис: if булевское_выражение оператор [else [if булевское_выражение] оператор ] Булевское выражение это выражение, значением которого является истина (TRUE) или ложь (FALSE). Оно может состоять из названий табличных столбцов и констант, соединенных арифметическими или булевскими операциями, или подзапросов, если эти подзапросы возвращают одно (скалярное) значение. Если булевское выражение содержит оператор выбора select, то этот оператор должен быть заключен в скобки и должен возвращать скалярное (невекторное) значение. Далее приводится пример условного оператора, который содержит только условие if и одну команду: if exists (select postalcode from authors where postalcode = '94705') print
"Berkeley author" В этом примере будет выводиться сообщение “Berkeley author”, если почтовые индексы некоторых авторов из таблицы authors равны “94705”. Оператор выбора в этом примере возвращает скалярное значение, которое равно либо TRUE либо FALSE, поскольку перед ним указано ключевое слово exists (существует). Ключевое слово exists действует здесь точно также, как и в подзапросах (см. главу 5 “Подзапросы: использование запросов внутри других запросов”). В следующем примере используются оба ключевых слова if и else. Здесь проверяется наличие объектов, созданных пользователями, которым присваиваются идентификационные номера, большие 50. Если такие объекты существует, то они выбираются из таблицы в конструкции else и для каждого из них указывается название, тип и номер. if (select max(id) from
sysobjects) < 50 print "There are no user-created
objects in this database." else select name, type, id from sysobjects where id > 50 and type = "U" (Выбрана 1
строка) name type id ------------
-------------- authors U 1088006907
publishers U 1120007021 roysched U 1152007135 sales U 1184007249 titleauthor U
1216007363 titles U 1248007477 stores U 1280007591 discounts U 1312007705 test U 1648008902 (Выбрано 9
строк) Условный оператор часто используется в сохраненных процедурах для проверки наличия некоторого параметра. Условие проверки может указываться внутри другого условия либо в части if либо в части else. Условие проверки должно иметь скалярное значение. В каждой части условного оператора может быть только по одному SQL оператору. Чтобы указать несколько SQL операторов, необходимо использовать операторные скобки begin…end. Максимальное число вложенных друг в друга условий проверки if зависит от сложности операторов выбора (или других языковых конструкций), которые используются в условном операторе. Ключевые слова begin и end используются как операторные скобки для выделения единого блока операторов, который может использоваться, например, в условном операторе. Последовательность операторов, заключенная в скобки begin и end, называется операторным блоком. Конструкция begin…end имеет следующий вид: begin блок операторов end Рассмотрим следующий пример: if (select avg(price) from
titles) < $15 begin update titles set price = price * 2 select title, price from titles where price > $28 end В этом примере без ключевых слов begin и end условие if относилось бы только к первому SQL оператору этого блока. Второй и последующие операторы выполнялись бы независимо от выполнения этого условия. Операторный блок begin…end можно включать внутрь другого операторного блока begin…end. Циклический оператор while и команды break…continue
Команда while (до тех пор, пока) используется для циклического (повторного) выполнения оператора или блока операторов. Операторы выполнятся до тех пор, пока истинно указанное условие. Эта команда имеет следующий вид: while булевское_выражение оператор
В следующем примере операторы select и update будут выполняться в цикле, пока средняя цена книги будет меньше $30: while (select
avg(price) from titles) < $30 begin select title_id, price from titles where price > $20 update titles set price = price * 2 end (Выбрано 0
строк) title_id
price ------
------- PC1035 22.95 PS1372 21.59 TC3218 20.95 (Выбрано 3
строки) (Выбрано 10
строк) (Выбрано 0 строк) title_id
price ------
------- BU1032 39.98 BU1111 23.90 BU7832 39.98 MC2222 39.98 PC1035 45.90 PC8888 40.00 PS1372 43.18 PS2091 21.90 PS3333 39.98 TC3218 41.90 TC4203 23.90 TC7777 29.98 (Выбрано 12
строк) (Выбрано 18
строк) (Выбрано 0
строк) Команды break (прервать) и continue (продолжить) управляют последовательностью выполнения операторов внутри цикла while. Команда break прекращает выполнение цикла. После этого управление передается оператору, следующему за ключевым словом end, которое указывает на конец цикла. Команда continue передает управление на начало цикла, поэтому все операторы, расположенные внутри цикла и следующие за этой командой, выполняться не будут. Командам break и continue часто предшествует проверка некоторого условия. Синтаксис команд break и continue имеет следующий вид: while булевское_выражение begin оператор …. [оператор] break [оператор] …. continue …. [оператор] end Далее приводится пример использования команд while, break, continue и if, в котором производится действие, обратное инфляционному действию предыдущего примера. До тех пор пока средняя цена книги остается большей $20, все цены уменьшаются наполовину. Затем выбирается максимальная цена. Если она меньше 40 долларов, то происходит выход из цикла, в противном случае цикл выполняется снова. Команда continue не допустит выполнение оператора вывода (печати) print, если средняя цена меньше $20. После окончания цикла while в этом примере выводится список самых дорогих книг и информационное сообщение "Not Too Expensive" (Не очень дорого). while (select
avg(price) from titles) > $20 begin update titles set price = price / 2 if (select max(price) from titles) <
$40 break else if (select avg(price) from
titles)
< $20 continue print "Average price still over
$20" end select
title_id, price from titles where price > $20 print
"Not Too Expensive" Average price still over $20 title_id
price --------
------- PC1035
22.95 PS1372
21.59 TC3218
20.95 (Выбрано 3 строки) Not Too Expensive Если циклы while вложены друг в друга, то команда break возвращает управление в наименьший внешний цикл, который содержит данный цикл. После этого возобновляется выполнение этого внешнего цикла с самого начала. Оператор declare и локальные переменные
Переменная - это объект, которому присваивается некоторое значение. Это значение может изменяться в процессе исполнения пакета или сохраненной процедуры, в которых используется эта переменная. У SQL Сервера имеется два вида переменных: локальные и глобальные. Локальные переменные определяются пользователем, в то время как глобальные переменные являются системными и определяются заранее. Для задания локальных переменных используется ключевое слово declare (объявить), после которого следует указать название переменной, ее тип. После этого переменной можно присвоить начальное значение с помощью оператора выбора. Локальные переменные можно использовать только в том пакете или процедуре, в которых они объявлены. Локальные переменные часто используются в пакетах или процедурах как счетчики циклов в операторе while, а также внутри операторного блока if…else. Когда переменные используются в сохраненной процедуре, они должны быть объявлены как автоматические для неинтерактивного использования во время выполнения сохраненной процедуры. Названия локальных переменных должны начинаться со знака “@” и отвечать правилам, установленным для идентификаторов. Для каждой локальной переменной нужно указать ее тип, который может быть задан пользователем или определяться системой, но не совпадать ни с одним из системных типов text, image, sysname. Объявление локальных переменных имеет следующий вид: declare @название_переменной тип_данных [,@название_переменной тип_данных] … После объявления переменной она имеет значение NULL. Чтобы присвоить ей значение следует использовать оператор выбора. Этот оператор имеет следующий синтаксис: select @название_переменной = { выражение | (оператор_выбора) } [, @название_переменной = { выражение | (оператор_выбора) } … ] [from конструкция] [where конструкция] [group by конструкция] [having конструкция] [order by конструкция] [compute конструкция] Локальные переменные должны объявляться в том же пакете или процедуре, в которых они используются. Оператор выбора, с помощью которого переменной присваивается значение обычно возвращает одно значение. Подзапрос, который возвращает значение для локальной переменной должен возвращать только одно значение. Далее приводятся несколько примеров присваивания значений переменным: declare
@veryhigh money select
@veryhigh = max(price) from titles if @veryhigh
> $20 print "Ouch!" declare @one
varchar(18), @two varchar(18) select @one =
"this is one", @two = "this is two" if @one =
"this is one" print "you got one" if @two =
"this is two" print "you got two" else print
"nope" declare
@tcount int, @pcount int select @tcount
= (select count(*) from titles), @pcount = (select count(*) from publishers)
select @tcount, @pcount Если оператор выбора возвращает более одного значения, то переменной присваивается последнее возвращаемое значение. С точки зрения эффективного использования памяти и времени лучше использовать оператор: select @a=1, @b=2,
@c=3 по сравнению с оператором: select @a=1 select @b=2 select @c=3 То же правило применимо к оператору declare. Гораздо более эффективно выполняется оператор: declare @a
int, @b char(20), @c float по сравнению с последовательностью операторов: declare @a int declare @b
char(20) declare @c float Оператор выбора, который присваивает значение локальной переменной, можно использовать только для этой цели. Его нельзя использовать для выборки данных из таблицы пользователя. В следующем примере первый оператор выбора присваивает значение локальноц переменной @veryhigh, но для вывода ее значения необходимо использовать второй оператор выбора: declare
@veryhigh money select
@veryhigh = max(price) from titles select
@veryhigh Если оператор выбора, который присваивает значение переменной, возвращает более одного значения, то переменной присваивается последнее возвращаемое значение. В следующем примере переменной присваивается последнее возвращаемое значение аванса из таблицы titles: declare @m
money select @m =
advance from titles select @m (Выбрано 18 строк) ------------------------
8,000.00 (Выбрана 1
строка) Заметим, что оператор выбора, присваивающий значение переменной, также выводит число строк, которые были при этом выбраны. Если оператор выбора, присваивающий значение переменной, не возвращает никакого значения, то значение переменной не изменяется. Локальные переменные могут использоваться как аргументы в
командах print и raiserror. После объявления локальной переменной ей присваивается неопределенное значение NULL. Кроме того, это значение можно присвоить с помощью оператора выбора. Предусмотрены специальные правила сравнения неопределенных значений переменных с другими значениями. В следующей таблице приведены результаты сравнения неопределенного значения, находящегося в столбце таблицы, с неопределенным значением выражения при выполнении различных операций сравнения. (Выражение может быть переменной, литералом или комбинацией переменных и литералов, соединенных арифметическими операциями). Таблица 13-2: Сравнение неопределенных значений
Например, в следующем примере только первое сравнение дает положительный результат: declare @v int, @i int if @v = @i select "null = null, true" if @v > @i select "null > null, true" -----------------
null = null,
true (Выбрана 1
строка) В следующем примере из таблицы titles выбираются все строки, в которых значение аванса (advance) является неопределенным: declare @m money select title_id, advance from titles where advance = @m title_id
advance --------
---------------- MC3026
NULL PC9999
NULL Оператор declare и
глобальные переменные
Глобальные переменные являются заранее определенными системными переменными. Названия глобальных переменных отличаются от локальных двумя, расположенными впереди, знаками “@”, например, @@error. В следующей таблице приводится список глобальных переменных. Таблица 13-3: Глобальные переменные SQL Сервера
С помощью системной процедуры sp_monitor (монитор) можно получить информацию о многих из этих глобальных переменных. Полная информация о системных процедурах приводится в Справочном руководстве SQL Сервера. Если пользователь объявляет локальную переменную, название которой совпадает с глобальной переменной, то эта переменная рассматривается как локальная. Команда goto (перейти на) вызывает безусловный переход на указанную пользователем метку. Эту команду перехода и метки можно использовать в пакетах и сохраненных процедурах. Название метки должно отвечать правилам, установленным для идентификаторов, и должно заканчиваться двоеточием, когда оно приводится впервые. Но двоеточие не нужно указывать, когда метка используется для ссылки в команде goto. Эта команда имеет следующий вид: метка: goto метка Далее приводится пример использования меток и команды безусловного перехода, команды цикла while и локальной переменной, которая используется в качестве счетчика: declare @count
smallint select @count
= 1 restart: print
"yes" select @count
= @count + 1 while @count
<=4 goto restart Как и в этом примере, команде перехода обычно предшествует проверка некоторого условия с помощью команд while или if, чтобы избежать появления бесконечного цикла между командой goto и меткой. Команда return (возврат) предназначена для безусловного выхода из пакета или процедуры. Она может использоваться в любом месте пакета или процедуры. Когда она используется в сохраненной процедуре, то ее можно дополнить аргументом для возврата состояния вызывающей процедуре. Операторы, расположенные после оператора возврата, не исполняются. Эта команда имеет следующий простой вид: return [int_выражение] В следующем примере в сохраненной процедуре используется оператор return вместе с условным оператором и операторными скобками begin…end: create
procedure findrules @nm varchar(30) = null as if @nm is null
begin print "You must give a user name" return end else begin select sysobjects.name, sysobjects.id,
sysobjects.uid from sysobjects, master..syslogins where master..syslogins.name = @nm and sysobjects.uid = master..syslogins.suid
and
sysobjects.type = "R" end Если процедуре findrules (найти правила) не задается имя пользователя в качестве параметра, то команда return вызывает выход из процедуры после сообщения, выдаваемого на экран пользователя. Если имя задано, то из соответствующих системных таблиц выбираются все правила, принадлежащие данному пользователю. По своему действию команда return аналогична команде break, которая используется для выхода из цикла. Примеры возврата значений с помощью этой команды приводятся в главе 14 “Использование сохраненных процедур”. Команда print (печатать), которая уже использовалась в предыдущих примерах, предназначена для вывода на экран сообщений пользователя или значений локальных переменных. Локальная переменная должна быть объявлена в том же пакете или процедуре, где она используется. Выводимое сообщение должно быть не длиннее 255 байт. Эта команда имеет следующий вид: print {форматированная_строка_вывода | @локальная_переменная | @@глобальная_переменная} [, список_аргументов] Приведем пример использования этой команды: if exists
(select postalcode from authors where postalcode = '94705') print
"Berkeley author" В следующем примере команда print используется для вывода значения локальной переменной: declare @msg
char(50) select @msg =
"What's up doc?" print @msg В команде print можно использовать форматные символы (placeholders). В выводимой строке можно указать до 20 таких символов, расположенных в любом порядке. Эти символы заменяются форматированными строками, указанными в списке аргументов, следующими за выводимой строкой, когда текст сообщения передается клиенту. Форматные символы нумеруются, чтобы можно было изменить порядок следования аргументов, когда выводимая строка должна быть переведена на язык с другой грамматической структурой. Форматные символы для аргументов имеют следующий вид: %nn!. Вначале указывается символ процентов, за которым следует целое число от 1 до 20, заканчивающееся восклицательным знаком. Целое число указывает позицию соответствующего аргумента в строке на исходном языке. Например, “%1!” указывает на позицию первого аргумента в строке, “%2!” второго и т.д. Такое указание позиции аргумента позволяет корректно перевести фразу на различные языки, даже в том случае, когда при переводе необходимо изменить порядок слов. Например, предположим, что выдается следующее сообщение на английском: %1! is not allowed in %2!. (%1! не
допускается в %2!.) На немецком языке это сообщение будет выглядеть следующим образом: %1! ist in %2! nicht zulаssig. В этом примере %1! во всех языках представляет собой один и тот же первый аргумент, а %2! второй аргумент. В этом примере также можно увидеть изменение расположения аргументов, когда фраза переводится на другой язык. Аргументы нужно нумеровать последовательно, хотя порядок расположения аргументов может и не соответствовать их порядковым номерам. Например, нельзя использовать 1 и 3 аргументы, когда в выводимой строке нет 2 аргумента. Необязательный список_аргументов может быть последовательностью переменных и констант. Аргумент может иметь любой тип за исключением text (текстовый) и image (графический). Аргумент конвертируется в тип char (символьный) перед тем, как помещается в окончательное сообщение. Если аргументов нет, то исходная строка выводится в том виде, в каком она задана и в этом случае в ней не должны быть никаких форматных символов. Максимальная длина выводимой строки с уже подставленными аргументами составляет 512 байт. Команда raiserror (возникновение ошибки) выводит на экран пользователя сообщение об ошибке и устанавливает системный флаг, который фиксирует факт возникновения ошибки. Как и в команде print здесь в качестве сообщения может выступать значение локальной переменной, но в этом случае локальная переменная должна быть объявлена в том же пакете или процедуре, где она используется. Сообщение должно быть не длиннее 255 символов. Команда raiserror имеет следующий вид: raiserror номер_ошибки [{форматированная_строка_вывода | @локальная_переменная }] [,список_аргументов] [extended_value
= extended_value [{, extended_value = extended_value }...]] Номер_ошибки запоминается в глобальной переменной @@error, которая содержит последний номер системной или пользовательской ошибки, выданный SQL Сервером. Номера ошибок для сообщений, которые выдаются пользователями, должны быть больше 17000. Если номер_ошибки находится между 17000 и 19999 и выводимая строка отсутствует или пуста (“”), то SQL Сервер выбирает текст сообщения об ошибке из системной таблицы sysmessages базы данных master. Эти сообщения об ошибке используются главным образом системными процедурами. Длина форматированной_строки_вывода самой по себе не должна превышать 255 байтов. Длина окончательного сообщения вместе с подставленными аргументами составляет 512 байтов. Локальные переменные используемые для вывода сообщения должны иметь тип char или varchar. Можно не указывать выводимую строку или локальную переменную. В этом случае SQL Сервер использует сообщение из таблицы sysusermessages, которое соответствует указанному номеру ошибки. Как и команде print здесь можно подставлять в выводимую строку значения констант или переменных, задав их в качестве аргументов. В качестве опции можно определить дополнительные значения ошибки для использования в Open Client (открытый клиент) приложении. В этом случае в команду raiserror нужно включить конструкцию extended_value (дополнительное значение). Более детальную информацию о дополнительных значениях ошибки можно посмотреть в документации по Open Client приложениям или в разделе о команде raiserror в Справочном руководстве SQL Сервера. Команду raiserror следует использовать вместо команды print, когда необходимо запомнить номер ошибки в переменной @@error. Например, в процедуре findrules можно было бы использовать следующее сообщение об ошибке: raiserror
99999 "You must give a user name"
(Нужно указать имя
пользователя). Уровень строгости (severity) всех сообщений об ошибках, выдаваемых пользователями, равен 16. Этот уровень указывает, что у пользователя возникла нефатальная ошибка. Сообщения пользователя в командах print и raiserror
Пользователь может выбирать сообщения из таблицы sysusermessages (системные сообщения пользователя) с помощью системной процедуры sp_getmassage (выдать сообщение) для их последующего использования в командах print или raiserror. Для записи сообщений в эту таблицу следует использовать системную процедуру sp_addmassage (добавить сообщение). В следующем примере демонстрируется использование процедур sp_getmassage, sp_addmassage и команды print для записи сообщений в таблицу sysusermessages как на английском, так на немецком языке, с последующим их использованием в сохраненной процедуре и выводом на экран: /* ** Install
messages ** First, the
English (langid = NULL) */ set language
us_english go sp_addmessage
25001, "There is already a remote user named
'%1!' for remote server '%2!'." go /* Then
German*/ sp_addmessage
25001, "Remotebenutzername '%1!' existiert
bereits auf dem Remoteserver '%2!'.","german" go create
procedure test_proc @remotename varchar(30), @remoteserver varchar(30) as declare @msg varchar(255) declare @arg1 varchar(40) /* ** check to make sure that there is
not ** a @remotename for the
@remoteserver. */ if exists (select * from master.dbo.sysremotelogins l, master.dbo.sysservers s where l.remoteserverid = s.srvid and s.srvname = @remoteserver and l.remoteusername =
@remotename) begin exec sp_getmessage 25001, @msg
output select
@arg1=isnull(@remotename,"null") print @msg, @arg1, @remoteserver return (1) end return(0) go Команда waitfor (ожидать до) предназначена задержки исполнения блока операторов, сохраненной процедуры или транзакции до наступления указанного времени, истечения временного интервала или наступления некоторого события. Эта команда имеет следующий синтаксис: waitfor {delay "время" | time "время" | errorexit | processexit | mirrorexit} Ключевое слово delay (задержка) сообщает SQL Серверу, что нужно ожидать до истечения указанного временного интервала. Ключевое слово time (время) сообщает SQL Серверу, что нужно ожидать до указанного момента времени, который должен быть задан в одном из форматов типа datetime. Однако при этом нельзя указывать календарные даты, поскольку календарная часть даты здесь не допускается. Время задержки, которое указывается в операторах waitfor time или waitfor delay, может включать часы, минуты, секунды, и оно не должно быть больше 24 часов. Для указания времени следует использовать формат “чч:мм:сс”. Например, команда waitfor time “16:23” сообщает SQL Серверу, что нужно ожидать до 16 часов 23 минут. Оператор waitfor delay “01:30” задерживает исполнение на один час 30 минут. Форматы указания времени можно также посмотреть в главе 8 “Добавление, изменение и удаление данных”. Ключевое слово errorexit (выход по ошибке) сообщает SQL Серверу, что нужно ожидать до тех пор, пока процесс завершится ненормально. Ключевое слово processexit (выход по выполнению) сообщает SQL Серверу, что нужно ожидать до тех пор, пока процесс завершится по какой-либо причине. Ключевое слово mirrorexit (выход по зеркалу) сообщает SQL Серверу, что нужно ожидать до тех пор, пока не появится ошибка по чтению или записи на одном из зеркальных (mirror) устройств. Команда waitfor errorexit обычно используется для удаления процесса, который закончился ошибкой, чтобы освободить системные ресурсы. Чтобы проверить какой процесс оказался ошибочным, следует посмотреть таблицу sysprocesses (системные процессы) с помощью системной процедуры sp_who. В следующем примере SQL Сервер ожидает наступления 14 часов 20 минут. Затем обновляется таблица chess (шахматы), в которую записывается очередной ход и исполняется сохраненная процедура sendmessage (послать сообщение), которая вставляет это сообщение в одну из таблиц Джуди (Judy), указывая ей тем самым, что сделан очередной ход шахматной партии. Этот пример имеет следующий вид: begin waitfor time
"14:20" insert
chess(next_move) values('Q-KR5')
execute
sendmessage 'judy' end Чтобы Джуди получила сообщение через 10 секунд, а не 14:20, нужно изменить команду ожидания следующим образом: waitfor delay "0:00:10" После выдачи команды waitfor нельзя использовать связь с SQL Сервером до тех пор, пока истечет указанный промежуток времени или наступит соответствующее событие. Комментарии обычно вносятся в операторы, пакеты и сохраненные процедуры для лучшего их понимания. Комментарий выглядит следующим образом: /* Текст комментария */ На длину комментариев не накладывается никаких ограничений и они могут вносится в любое место, либо в виде отдельной строки, либо в конце строки. Допускаются также комментарии, занимающие несколько строк, но при этом каждая строка должна начинаться с наклонной черты (слеша) и звездочки и заканчиваться звездочкой и слешем. Все, что находиться между символами “/*” и “*/”, рассматривается как комментарий. Комментарии могут быть вложенными друг в друга. Для длинных комментариев, занимающих несколько строк, вводится также следующее стилистическое соглашение. Комментарий должен начинаться символами “/*”, а все последующие строки двумя звездочками “**”. Такой комментарий, как обычно, должен заканчиваться символами “*/”. В следующем примере можно увидеть подобный комментарий: select * from
titles /* A comment
here might explain the rules ** associated
with using an asterisk as ** shorthand
in the select list.*/ where price > $5 В следующем примере приводится процедура вместе с сопровождающими ее комментариями: /* this
procedure finds rules by user name*/ create
procedure findrules2 @nm varchar(30) = null as if @nm is
null /*if no parameter is given*/ print
"You must give a user name" else begin select sysobjects.name, sysobjects.id, sysobjects.uid from sysobjects, master..syslogins where master..syslogins.name = @nm and sysobjects.uid = master..syslogins.suid
and sysobjects.type = "R" end
|
Дизайн: Piton Alien |