Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Пакеты и язык управления заданиями

01.01.2007

Пакеты и язык управления заданиями

 

Язык 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 ложно.

Begin

Начало блока операторов.

…end

Конец блока операторов.

While

Циклическое выполнение операторов, пока условие, указанное в while истинно.

Break

Принудительный выход из цикла.

…continue

Повторить выполнение цикла while.

Declare

Объявление локальной переменной.

goto label

Переход на метку (label), которая расположена в блоке операторов.

Return

Безусловный выход.

Waitfor

Установить задержку на выполнение команды.

Print

Вывести на экран сообщение, которое указано пользователем или хранится в локальной переменной.

Raiserror

Вывести на экран сообщение об ошибке, указанное пользователем или хранящееся в локальной переменной, и установить глобальную переменную @@error (ошибка).

/* comment */

Внести комментарий (комментарий можно указать в любом месте SQL оператора).
 

Условный оператор 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 имеет следующий вид:

 

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: Сравнение неопределенных значений

 

Операции =, !=, <>

Операции <, >, <=, !<, !>

Сравнение табличного_значения с табличным_значением

FALSE

FALSE

Сравнение табличного_значения с выражением

TRUE

FALSE

Сравнение выражения с табличным_значением

TRUE

FALSE

Сравнение выражения с выражением

TRUE

FALSE

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

 

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 Сервера

 

Переменная

Значение

@@char_convert

Равна 0, если не установлено преобразование алфавитов (множества символов). Равна 1, если такое преобразование установлено.

@@client_csname

Содержит название алфавита клиента. Равна NULL, если алфавит клиента никогда не инициализировался, в противном случае содержит название последнего использованного алфавита.

@@client_csid

Содержит идентификатор алфавита клиента. Устанавливается в -1, если алфавит клиента никогда не инициализировался, в противном случае содержит идентификатор последнего использованного алфавита из таблицы syscharset.

@@connections

Равна числу зарегистрированных входов в систему (logins) или попыток регистраций.

@@cpu_busy

Равна времени (в тактах процессора) загрузки процессора задачами SQL Сервера, начиная с последнего старта SQL Сервера.

@@error

Равна 0, если последняя транзакция была успешно выполнена. В противном случае, содержит последний номер ошибки, выданный системой. Эта переменная часто используется для проверки ошибок после исполнения последнего оператора. Оператор типа if @@error != 0 return используется для выхода при возникновении ошибки.

@@identity

Содержит последний номер, записанный в столбец счетчика оператором insert или select  into. Эта переменная изменяется при вставке каждой новой строки. Если оператор вставляет несколько строк, то данной переменной присваивается номер последней строки. Если в изменяемой таблице нет счетчика, то данной переменной присваивается 0.

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

@@idle

Равна количеству времени (в тактах процессора), в течении которого у SQL Сервера не было работы.

@@io_busy

Равна количеству времени (в тактах процессора), в течении которого SQL Сервер выполнял операции ввода-вывода.

@@isolation

Указывает на уровень изоляции Transact-SQL программы. Этот уровень может изменяться от 1 до 3.

@@langid

Указывает на идентификатор текущего языка, который берется из таблицы идентификаторов syslanguges.langid.

@@language

Указывает на название текущего языка, который берется из таблицы syslanguges.name.

@@maxcharlen

Указывает на максимальную длину (в байтах) символа из мультибайтового алфавита.

@@max_connections

Указывает на максимальное число соединений, которые могут быть установлены с SQL Сервером в данной вычислительной среде. Пользователь может установить любое число соединений, не превосходящее значения этой переменной, с помощью процедуры sp_configure ‘number of user connections’.

@@ncharsize

Равно средней длине (в байтах) символа национального алфавита.

@@nestlevel

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

@@pack_received

Указывает на число входных пакетов (packet), прочитанных SQL Сервером.

@@pack_sent

Указывает на число выходных пакетов (packet), записанных SQL Сервером.

@@pack_errors

Указывает на число ошибок, которые возникли во время получения или пересылки пакетов.

@@procid

Содержит идентификатор выполняемой в данный момент сохраненной процедуры.

@@rowcount

Указывает на число строк, которые обрабатывались в последнем запросе. Эта переменная устанавливается в ноль любой командой, которая не работает со строками, как например, оператор if.

@@servername

Содержит название данного SQL Сервера.

@@spid

Указывает серверный идентификатор текущего процесса.

@@sqlstatus

Содержит информацию о состоянии, выданную последним оператором fetch (вызвать).

@@textcolid

Содержит идентификатор столбца, на который ссылается текстовый указатель, хранящийся в глобальной переменной @@textptr. Эта переменная имеет тип tinyint.

@@textdbid

Указывает идентификатор базы данных, которая содержит столбец, на который ссылается указатель, хранящийся в переменной @@textptr. Эта переменная имеет тип smallint.

@@textobjid

Указывает идентификатор объекта, который содержит столбец, на который ссылается текстовый указатель переменной @@textptr. Эта переменная имеет тип int.

@@textptr

Содержит текстовый указатель, который использовался при последнем обращении к тестовому или графическому столбцу. Эта переменная имеет тип binary(16). Не следует путать эту переменную с функцией textptr.

@@textsize

Указывает на максимальное число байтов, которые можно выбрать из текстового или графического поля оператором select. Для утилиты isql по умолчанию это значение равно 32К, но значение, принимаемое по умолчанию, зависит от программного обеспечения клиента. Значение этой переменной для данной сессии можно установить командой set textsize.

@@textts

Указывает на момент последнего обращения к текстовому столбцу, на который указывает переменная @@textptr. Эта переменная имеет тип varbinary(8).

@@tresh_hysteresis

Указывает на минимально допустимую величину свободной памяти, после которой необходимо активизировать порог (threshold). Эта величина, известная также как величина гистерезиса (hysteresis), измеряется в страницах размера 2К. Она определяет насколько близко пороги могут быть расположены в сегменте базы данных.

@@timeticks

Указывает длительность такта процессора в микросекундах. Эта величина, конечно, является машинно-зависимой.

@@totalerrors

Указывает на общее число ошибок, возникших в процессе передачи данных SQL Сервером.

@@total_read

Указывает на число чтений с диска, которые SQL Сервер выполнил со времени последнего старта.

@@total_write

Указывает на число записей с диска, которые SQL Сервер выполнил со времени последнего старта.

@@tranchained

Указывает на текущий режим транзакций Transact-SQL программы. Значение этой переменной равно 0, если установлен несвязный (unchained) режим и 1, если связный.

@@trancount

Указывает число активных транзакций текущего пользователя.

@@transtate

Указывает текущее состояние транзакции после выполнения оператора. Но в отличии от переменной @@error, эта переменная не очищается после выполнения каждого оператора.

@@version

Указывает дату создания текущей версии SQL Сервера.

С помощью системной процедуры sp_monitor (монитор) можно получить информацию о многих из этих глобальных переменных. Полная информация о системных процедурах приводится в Справочном руководстве SQL Сервера.

Если пользователь объявляет локальную переменную, название которой совпадает с глобальной переменной, то эта переменная рассматривается как локальная.

 

Команда перехода goto
 

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

Эта команда имеет следующий простой вид:

 

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
 

Команда 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
 

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

Эта команда имеет следующий синтаксис:

 

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