Пакеты и язык управления заданиями
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 метка
Далее приводится пример использования меток и команды безусловного перехода, команды цикла 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