I’m getting this error from the function:
CREATE FUNCTION getLavel(@id int ,@lavel char)
RETURNS date
BEGIN
DECLARE @date date
select @date = (select authorization_date from Authorized WHERE diver_number = @id and @lavel =level_name)
return @date
END
GO
What can be the reason?
Ty very much.
juergen d
201k36 gold badges290 silver badges357 bronze badges
asked Jul 28, 2014 at 19:31
3
The function needs to be either the only function in the query window OR the only statement in the batch. If there are more statements in the query window, you can make it the only one «in the batch» by surrounding it with GO’s.
e.g.
GO
CREATE FUNCTION getLavel(@id int ,@lavel char)
RETURNS date
BEGIN
DECLARE @date date
select @date = (select authorization_date from Authorized WHERE diver_number = @id and @lavel =level_name)
return @date
END
GO
answered May 28, 2015 at 8:54
nicVnicV
6307 silver badges16 bronze badges
1
Turn this into an inline table valued function. This will perform better than the scalar function. Also, you should NOT use the default sizes for character datatypes. Do you know what the default length for a char is? Did you know that it can vary based on usage?
CREATE FUNCTION getLavel
(
@id int
, @lavel char --You need to define the length instead of the default length
)
RETURNS table
return
select authorization_date
from Authorized
WHERE diver_number = @id
and @lavel = level_name
GO
answered Jul 28, 2014 at 19:38
Sean LangeSean Lange
32.9k3 gold badges24 silver badges39 bronze badges
5
You need to add RETURN before the END statement
That should fix your issue, that’s what fixed mine.
answered Sep 22, 2015 at 17:58
FoxArcFoxArc
1149 bronze badges
Make sure that this statement is the only the only sql in your query window before you execute it.
Or you can highlight the function declaration and execute
Ben Thul
30.8k4 gold badges45 silver badges68 bronze badges
answered Jul 28, 2014 at 19:35
What solved it for me, was that I was trying to create the function inside of a transaction context — that doesn’t make sense from a SQL Server point of view. Transactions are for data, not functions.
Take the CREATE FUNCTION statement out of the transaction, then wrap it in GO’s
answered Dec 10, 2017 at 20:05
CREATE FUNCTION CalculateAge(@DOB DATE)
RETURNS INT
AS
BEGIN
DECLARE @Age INT
SET @DOB='08/12/1990'
SET @Age =DATEDIFF(YEAR,@DOB,GETDATE()) -
CASE
WHEN (MONTH (@DOB)> MONTH (GETDATE ())) OR
(MONTH (@DOB)= MONTH (GETDATE ()) AND DAY (@DOB) >DAY (GETDATE ()))
THEN 1
ELSE 0
END
SELECT @Age
END
Tunaki
131k46 gold badges331 silver badges417 bronze badges
answered Jun 14, 2016 at 10:38
1
The Error is given to you in only query Page But if you execute the query then it will successfully execute.
CREATE FUNCTION getLavel(@id int ,@lavel char)
RETURNS date
BEGIN
DECLARE @date date
select @date = (select authorization_date from Authorized WHERE diver_number = @id and @lavel = level_name)
return @date
END
GO
answered Oct 25, 2020 at 12:29
Вам необходимо убрать ключевое слово BEGIN перед началом создания функции, т.к. это вызывает синтаксическую ошибку: «CREATE FUNCTION» должна быть единственной в пакете
Для вызова каждого параметра по умолчанию, необходимо передать ключевое слово DEFAULT в верхнем регистре
Код должен выглядеть следующим образом
CREATE FUNCTION funkcja(@p1 int = 18, @p2 int = 30)
RETURNS TABLE
AS
RETURN (SELECT * FROM Employees
WHERE DATEDIFF(year, BirthDate, getdate()) between @p1 and @p2)
GO
BEGIN
SELECT EmployeeID, LastName, FirstName, ROW_NUMBER(order by employyID desc) as number
FROM funkcja(DEFAULT, DEFAULT)
WHERE number % 3 = 0
order by desc
GO
END;
#sql #sql-server #view #ssms
#sql #sql-сервер #Вид #ssms
Вопрос:
Microsoft SQL Server Management Studio 18 показывает ошибку:
CREATE VIEW должна быть единственной инструкцией в пакете
После выполнения запроса появляется следующая ошибка:
Неправильный синтаксис вокруг ключевого слова «select»
create view revenue0 (supplier_no, total_revenue) as
select
l_suppkey,
sum(l_extendedprice * (1 - l_discount))
from
lineitem
where
l_shipdate >= '1996-05-01'
and l_shipdate < dateadd(mm,3,cast('1996-05-01' as datetime))
group by
l_suppkey;
select
s_suppkey,
s_name,
s_address,
s_phone,
total_revenue
from
supplier,
revenue0
where
s_suppkey = supplier_no
and total_revenue = (
select
max(total_revenue)
from
revenue0
)
order by
s_suppkey
option (maxdop 2)
drop view revenue0
UPD. Я попытался запустить этот метод:
create view revenue0 (supplier_no, total_revenue) as
select
l_suppkey,
sum(l_extendedprice * (1 - l_discount))
from
lineitem
where
l_shipdate >= cast('1996-05-01' as datetime)
and l_shipdate < dateadd(mm, 3, cast('1996-05-01' as datetime))
group by
l_suppkey;
go
select
s_suppkey,
s_name,
s_address,
s_phone,
total_revenue
from
supplier,
revenue0
where
s_suppkey = supplier_no
and total_revenue = (
select
max(total_revenue)
from
revenue0
)
order by
s_suppkey;
drop view revenue0;
Но в результате выполнения запроса отображается ошибка:
Недопустимое имя объекта «revenue0».
Как только я не изменил свое имя. SQL все равно ругается на это имя.
UPD2. Вопрос был решен самостоятельно. Тема закрыта! Спасибо всем за ваши усилия!
Комментарии:
1. Поместите слово
GO
после определения представления.2. Можете ли вы сказать мне, где именно? Я не очень хорошо разбираюсь в SQL. Я буду очень благодарен!
3.
group by l_suppkey; GO
4. Неправильный синтаксис вокруг конструкции «go».
5. вы не можете использовать «order by» в представлении, измените свой вид, чтобы не использовать его.
Ответ №1:
Ошибка сообщает, что CREATE VIEW должен быть единственным оператором в пакете. Пакет завершается в SQL Server ключевым словом «GO», как заявил Гордон, поэтому ваш код должен выглядеть следующим образом:
create view revenue0 (supplier_no, total_revenue) as
select
l_suppkey,
sum(l_extendedprice * (1 - l_discount))
from
lineitem
where
l_shipdate >= '1996-05-01'
and l_shipdate < dateadd(mm,3,cast('1996-05-01' as datetime))
group by
l_suppkey;
GO -- right here. This ends a batch. Must be on a new line, with no semi-color, or SQL gets pissy.
select
s_suppkey,
s_name,
s_address,
s_phone,
total_revenue
from
supplier,
revenue0
where
s_suppkey = supplier_no
and total_revenue = (
select
max(total_revenue)
from
revenue0
)
order by
s_suppkey
option (maxdop 2);
drop view revenue0;
Комментарии:
1. Я тестирую «Тесты TPC-H на MS-SQL-Server» этот материал: ссылка . При выполнении этого запроса это должно быть: link .
2. Но у меня, с вашей поправкой, после выполнения SQL-запроса выводится пустая таблица. Время выполнения запроса составляет 0 секунд. Это ненормально.
3. Вы можете помочь переделать этот запрос, чтобы он работал: ссылка .
4. Я уже всю голову сломал с ним. Но этот конкретный запрос не хочет работать. Все остальные работают.
Вопрос:
Я пытаюсь сначала проверить, существует ли функция, и создать ее, если она не существует.
Я получаю эту ошибку от функции:
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[GetRelativeExpiry]') AND type in (N'U'))
BEGIN
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
CREATE FUNCTION [dbo].[GetRelativeExpiry]
(
@Date DATE,
@N INT
)
RETURNS DATE
AS
BEGIN
-- Declare the return variable here
DECLARE @Expiry as DATE;
IF @N > 0
BEGIN
SELECT @Expiry = MAX(E2.Expiry)
FROM (SELECT TOP(@N) Expiry
FROM ExpiryDates E1
WHERE E1.Expiry >= @date
ORDER BY E1.Expiry) AS E2
END
ELSE
BEGIN
SELECT @Expiry = MIN(E2.Expiry)
FROM (SELECT TOP(-@N) Expiry
FROM ExpiryDates E1
WHERE E1.Expiry <= @date
ORDER BY E1.Expiry DESC) AS E2
END
RETURN @Expiry
END
END
Я не уверен, почему я получаю эту ошибку, может кто-то может помочь? Я использую Microsoft SQL Server Management Studio 2014
Лучший ответ:
Если вы пытаетесь сделать это в обычном окне в MS SQL Server Management Studio 2014 (или любой предыдущей версии), где вы обычно записываете все другие запросы, то ваше определение функции должно быть очень первым утверждением, которое не комментируется.
См. Изображение ниже. Если инструкция USE PTCRMstaging_test;
не был прокомментирован, SQL Server Management Studio даст такую же ошибку.
Ответ №1
Операторы CREATE
, будь то для TYPE, PROCEDURE, FUNCTION,...
всегда должны быть первым оператором в пакете.
Чтобы обойти это в таких партиях, как ваш, выполните инструкцию CREATE
с помощью sp_executesql
следующим образом:
EXEC sp_executesql N'
-- your CREATE statement here
';
I’m getting this error from the function:
CREATE FUNCTION getLavel(@id int ,@lavel char)
RETURNS date
BEGIN
DECLARE @date date
select @date = (select authorization_date from Authorized WHERE diver_number = @id and @lavel =level_name)
return @date
END
GO
What can be the reason?
Ty very much.
juergen d
201k36 gold badges290 silver badges355 bronze badges
asked Jul 28, 2014 at 19:31
3
The function needs to be either the only function in the query window OR the only statement in the batch. If there are more statements in the query window, you can make it the only one «in the batch» by surrounding it with GO’s.
e.g.
GO
CREATE FUNCTION getLavel(@id int ,@lavel char)
RETURNS date
BEGIN
DECLARE @date date
select @date = (select authorization_date from Authorized WHERE diver_number = @id and @lavel =level_name)
return @date
END
GO
answered May 28, 2015 at 8:54
nicVnicV
6307 silver badges16 bronze badges
1
Turn this into an inline table valued function. This will perform better than the scalar function. Also, you should NOT use the default sizes for character datatypes. Do you know what the default length for a char is? Did you know that it can vary based on usage?
CREATE FUNCTION getLavel
(
@id int
, @lavel char --You need to define the length instead of the default length
)
RETURNS table
return
select authorization_date
from Authorized
WHERE diver_number = @id
and @lavel = level_name
GO
answered Jul 28, 2014 at 19:38
Sean LangeSean Lange
32.8k3 gold badges26 silver badges39 bronze badges
5
You need to add RETURN before the END statement
That should fix your issue, that’s what fixed mine.
answered Sep 22, 2015 at 17:58
FoxArcFoxArc
1149 bronze badges
Make sure that this statement is the only the only sql in your query window before you execute it.
Or you can highlight the function declaration and execute
Ben Thul
30.7k4 gold badges46 silver badges68 bronze badges
answered Jul 28, 2014 at 19:35
What solved it for me, was that I was trying to create the function inside of a transaction context — that doesn’t make sense from a SQL Server point of view. Transactions are for data, not functions.
Take the CREATE FUNCTION statement out of the transaction, then wrap it in GO’s
answered Dec 10, 2017 at 20:05
CREATE FUNCTION CalculateAge(@DOB DATE)
RETURNS INT
AS
BEGIN
DECLARE @Age INT
SET @DOB='08/12/1990'
SET @Age =DATEDIFF(YEAR,@DOB,GETDATE()) -
CASE
WHEN (MONTH (@DOB)> MONTH (GETDATE ())) OR
(MONTH (@DOB)= MONTH (GETDATE ()) AND DAY (@DOB) >DAY (GETDATE ()))
THEN 1
ELSE 0
END
SELECT @Age
END
Tunaki
131k46 gold badges330 silver badges415 bronze badges
answered Jun 14, 2016 at 10:38
1
The Error is given to you in only query Page But if you execute the query then it will successfully execute.
CREATE FUNCTION getLavel(@id int ,@lavel char)
RETURNS date
BEGIN
DECLARE @date date
select @date = (select authorization_date from Authorized WHERE diver_number = @id and @lavel = level_name)
return @date
END
GO
answered Oct 25, 2020 at 12:29
Всякий раз, когда я запускаю это вместе с другими инструкциями SQL, он выдает ошибку:
CREATE FUNCTION ‘должен быть первым оператором в пакете запроса
Однако всякий раз, когда я выполняю его один (без SELECT * FROM CUSTOMER в моем случае это работает)
SELECT * FROM CUSTOMER;
create function udfLogin
(@username nvarchar(100), @password nvarchar(100))
returns int as
begin
if exists(select 1 from CUSTOMER where Username = @username and [Password] = @password)
return 1
return 0;
end
3 ответа
Лучший ответ
Вы должны отделить каждую партию кода с помощью ключевого слова GO.
SELECT * FROM CUSTOMER
GO
create function udfLogin
(@username nvarchar(100), @password nvarchar(100))
returns int as
begin
if exists(select 1 from CUSTOMER where Username = @username and
[Password] = @password)
return 1
return 0;
end
Go
1
Mehrnoosh
27 Мар 2018 в 11:27
Как следует из сообщения об ошибке, оператор CREATE FUNCTION должен быть первым оператором в пакете запроса. Перед оператором CREATION FUNCTION не должно быть других операторов, которые сделали бы его не первым оператором в пакете запроса. Как следует из сообщения, чтобы избежать этой ошибки, оператор CREATE FUNCTION должен быть первым оператором в пакете запроса.
SQL выполняет инструкцию как пакет запроса.
Правила использования пакетов
Следующие правила применяются к использованию пакетов:
Операторы CREATE DEFAULT, CREATE FUNCTION, CREATE PROCEDURE, CREATE RULE, CREATE SCHEMA, CREATE TRIGGER и CREATE VIEW нельзя объединять с другими операторами в пакете. Оператор CREATE должен запустить пакет. Все остальные операторы, которые следуют в этом пакете, будут интерпретированы как часть определения первого оператора CREATE.
0
Karthik Venkatraman
27 Мар 2018 в 11:37
Вы должны включить разделитель партии, например, Go
SELECT * FROM CUSTOMER
GO
create function udfLogin
(@username nvarchar(100), @password nvarchar(100))
returns int as
begin
if exists(select 1 from CUSTOMER where Username = @username and [Password] = @password)
return 1
return 0;
end
Go
2
Mazhar
27 Мар 2018 в 11:26
Вопрос:
Я пытаюсь сначала проверить, существует ли функция, и создать ее, если она не существует.
Я получаю эту ошибку от функции:
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[GetRelativeExpiry]') AND type in (N'U'))
BEGIN
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
CREATE FUNCTION [dbo].[GetRelativeExpiry]
(
@Date DATE,
@N INT
)
RETURNS DATE
AS
BEGIN
-- Declare the return variable here
DECLARE @Expiry as DATE;
IF @N > 0
BEGIN
SELECT @Expiry = MAX(E2.Expiry)
FROM (SELECT TOP(@N) Expiry
FROM ExpiryDates E1
WHERE E1.Expiry >= @date
ORDER BY E1.Expiry) AS E2
END
ELSE
BEGIN
SELECT @Expiry = MIN(E2.Expiry)
FROM (SELECT TOP(-@N) Expiry
FROM ExpiryDates E1
WHERE E1.Expiry <= @date
ORDER BY E1.Expiry DESC) AS E2
END
RETURN @Expiry
END
END
Я не уверен, почему я получаю эту ошибку, может кто-то может помочь? Я использую Microsoft SQL Server Management Studio 2014
Лучший ответ:
Если вы пытаетесь сделать это в обычном окне в MS SQL Server Management Studio 2014 (или любой предыдущей версии), где вы обычно записываете все другие запросы, то ваше определение функции должно быть очень первым утверждением, которое не комментируется.
См. Изображение ниже. Если инструкция USE PTCRMstaging_test;
не был прокомментирован, SQL Server Management Studio даст такую же ошибку.
Ответ №1
Операторы CREATE
, будь то для TYPE, PROCEDURE, FUNCTION,...
всегда должны быть первым оператором в пакете.
Чтобы обойти это в таких партиях, как ваш, выполните инструкцию CREATE
с помощью sp_executesql
следующим образом:
EXEC sp_executesql N'
-- your CREATE statement here
';
#sql #sql-server #view #ssms
#sql #sql-сервер #Вид #ssms
Вопрос:
Microsoft SQL Server Management Studio 18 показывает ошибку:
CREATE VIEW должна быть единственной инструкцией в пакете
После выполнения запроса появляется следующая ошибка:
Неправильный синтаксис вокруг ключевого слова «select»
create view revenue0 (supplier_no, total_revenue) as
select
l_suppkey,
sum(l_extendedprice * (1 - l_discount))
from
lineitem
where
l_shipdate >= '1996-05-01'
and l_shipdate < dateadd(mm,3,cast('1996-05-01' as datetime))
group by
l_suppkey;
select
s_suppkey,
s_name,
s_address,
s_phone,
total_revenue
from
supplier,
revenue0
where
s_suppkey = supplier_no
and total_revenue = (
select
max(total_revenue)
from
revenue0
)
order by
s_suppkey
option (maxdop 2)
drop view revenue0
UPD. Я попытался запустить этот метод:
create view revenue0 (supplier_no, total_revenue) as
select
l_suppkey,
sum(l_extendedprice * (1 - l_discount))
from
lineitem
where
l_shipdate >= cast('1996-05-01' as datetime)
and l_shipdate < dateadd(mm, 3, cast('1996-05-01' as datetime))
group by
l_suppkey;
go
select
s_suppkey,
s_name,
s_address,
s_phone,
total_revenue
from
supplier,
revenue0
where
s_suppkey = supplier_no
and total_revenue = (
select
max(total_revenue)
from
revenue0
)
order by
s_suppkey;
drop view revenue0;
Но в результате выполнения запроса отображается ошибка:
Недопустимое имя объекта «revenue0».
Как только я не изменил свое имя. SQL все равно ругается на это имя.
UPD2. Вопрос был решен самостоятельно. Тема закрыта! Спасибо всем за ваши усилия!
Комментарии:
1. Поместите слово
GO
после определения представления.2. Можете ли вы сказать мне, где именно? Я не очень хорошо разбираюсь в SQL. Я буду очень благодарен!
3.
group by l_suppkey; GO
4. Неправильный синтаксис вокруг конструкции «go».
5. вы не можете использовать «order by» в представлении, измените свой вид, чтобы не использовать его.
Ответ №1:
Ошибка сообщает, что CREATE VIEW должен быть единственным оператором в пакете. Пакет завершается в SQL Server ключевым словом «GO», как заявил Гордон, поэтому ваш код должен выглядеть следующим образом:
create view revenue0 (supplier_no, total_revenue) as
select
l_suppkey,
sum(l_extendedprice * (1 - l_discount))
from
lineitem
where
l_shipdate >= '1996-05-01'
and l_shipdate < dateadd(mm,3,cast('1996-05-01' as datetime))
group by
l_suppkey;
GO -- right here. This ends a batch. Must be on a new line, with no semi-color, or SQL gets pissy.
select
s_suppkey,
s_name,
s_address,
s_phone,
total_revenue
from
supplier,
revenue0
where
s_suppkey = supplier_no
and total_revenue = (
select
max(total_revenue)
from
revenue0
)
order by
s_suppkey
option (maxdop 2);
drop view revenue0;
Комментарии:
1. Я тестирую «Тесты TPC-H на MS-SQL-Server» этот материал: ссылка . При выполнении этого запроса это должно быть: link .
2. Но у меня, с вашей поправкой, после выполнения SQL-запроса выводится пустая таблица. Время выполнения запроса составляет 0 секунд. Это ненормально.
3. Вы можете помочь переделать этот запрос, чтобы он работал: ссылка .
4. Я уже всю голову сломал с ним. Но этот конкретный запрос не хочет работать. Все остальные работают.
50 / 50 / 6 Регистрация: 16.05.2012 Сообщений: 232 |
|
1 |
|
Создание функции для определения скидки12.01.2015, 21:38. Показов 7510. Ответов 5
Необходимо написать функцию, которая в зависимости от стоимости покупки определяет скидку. Не представляю, как это можно сделать на T-SQL. 10000> 2% На вход поступает FLOAT — стоимость покупки, на выходе FLOAT — скидка поделенная на 100. 0 |
1312 / 944 / 144 Регистрация: 17.01.2013 Сообщений: 2,348 |
|
12.01.2015, 21:59 |
2 |
Функция называется CASE 0 |
T2skler 50 / 50 / 6 Регистрация: 16.05.2012 Сообщений: 232 |
||||
13.01.2015, 22:50 [ТС] |
3 |
|||
UP!
Я пытался Помогите функцию дописать, курсач из-за этого висит мёртвым грузом( 0 |
cygapb-007 1312 / 944 / 144 Регистрация: 17.01.2013 Сообщений: 2,348 |
||||
13.01.2015, 23:07 |
4 |
|||
Сообщение было отмечено T2skler как решение РешениеЕсли уж обязательно функцию (хотя не понимаю, зачем), то примерно так:
1 |
50 / 50 / 6 Регистрация: 16.05.2012 Сообщений: 232 |
|
14.01.2015, 15:33 [ТС] |
5 |
А кто подскажет, что за сообщение об ошибке: инструкция create function должна быть единственной в пакете? 0 |
4 / 4 / 1 Регистрация: 11.01.2015 Сообщений: 18 |
|
14.01.2015, 16:15 |
6 |
Это значит — кроме функции никаких других строк в запросе быть не должно. 0 |
Всякий раз, когда я запускаю это вместе с другими инструкциями SQL, он выдает ошибку:
CREATE FUNCTION ‘должен быть первым оператором в пакете запроса
Однако всякий раз, когда я выполняю его один (без SELECT * FROM CUSTOMER в моем случае это работает)
SELECT * FROM CUSTOMER;
create function udfLogin
(@username nvarchar(100), @password nvarchar(100))
returns int as
begin
if exists(select 1 from CUSTOMER where Username = @username and [Password] = @password)
return 1
return 0;
end
3 ответа
Лучший ответ
Вы должны отделить каждую партию кода с помощью ключевого слова GO.
SELECT * FROM CUSTOMER
GO
create function udfLogin
(@username nvarchar(100), @password nvarchar(100))
returns int as
begin
if exists(select 1 from CUSTOMER where Username = @username and
[Password] = @password)
return 1
return 0;
end
Go
1
Mehrnoosh
27 Мар 2018 в 11:27
Как следует из сообщения об ошибке, оператор CREATE FUNCTION должен быть первым оператором в пакете запроса. Перед оператором CREATION FUNCTION не должно быть других операторов, которые сделали бы его не первым оператором в пакете запроса. Как следует из сообщения, чтобы избежать этой ошибки, оператор CREATE FUNCTION должен быть первым оператором в пакете запроса.
SQL выполняет инструкцию как пакет запроса.
Правила использования пакетов
Следующие правила применяются к использованию пакетов:
Операторы CREATE DEFAULT, CREATE FUNCTION, CREATE PROCEDURE, CREATE RULE, CREATE SCHEMA, CREATE TRIGGER и CREATE VIEW нельзя объединять с другими операторами в пакете. Оператор CREATE должен запустить пакет. Все остальные операторы, которые следуют в этом пакете, будут интерпретированы как часть определения первого оператора CREATE.
0
Karthik Venkatraman
27 Мар 2018 в 11:37
Вы должны включить разделитель партии, например, Go
SELECT * FROM CUSTOMER
GO
create function udfLogin
(@username nvarchar(100), @password nvarchar(100))
returns int as
begin
if exists(select 1 from CUSTOMER where Username = @username and [Password] = @password)
return 1
return 0;
end
Go
2
Mazhar
27 Мар 2018 в 11:26
Программирование
Базы данных
Пакеты
и язык управления заданиями
Язык 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 |
Определяет |
Begin |
Начало |
…end |
Конец |
While |
Циклическое |
Break |
Принудительный |
…continue |
Повторить |
Declare |
Объявление |
goto label |
Переход |
Return |
Безусловный |
Waitfor |
Установить |
|
Вывести |
Raiserror |
Вывести |
/* comment */ |
Внести |
Условный оператор 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, если не установлено преобразование алфавитов |
@@client_csname |
Содержит название алфавита клиента. Равна NULL, если |
@@client_csid |
Содержит идентификатор алфавита клиента. Устанавливается в |
@@connections |
Равна числу зарегистрированных входов в систему (logins) |
@@cpu_busy |
Равна времени (в тактах процессора) загрузки процессора |
@@error |
Равна 0, если последняя транзакция была успешно выполнена. |
@@identity |
Содержит последний номер, записанный в столбец счетчика Значение этой переменной не меняется при ошибочном |
@@idle |
Равна количеству времени (в тактах процессора), в течении |
@@io_busy |
Равна количеству времени (в тактах процессора), в течении |
@@isolation |
Указывает на уровень изоляции Transact-SQL программы. Этот |
@@langid |
Указывает на идентификатор текущего языка, который берется |
@@language |
Указывает на название текущего языка, который берется из |
@@maxcharlen |
Указывает на максимальную длину (в байтах) символа из |
@@max_connections |
Указывает на максимальное число соединений, которые могут |
@@ncharsize |
Равно средней длине (в байтах) символа национального |
@@nestlevel |
Указывает на текущей уровень вложенности исполнения, |
@@pack_received |
Указывает на число входных пакетов (packet), прочитанных SQL Сервером. |
@@pack_sent |
Указывает на число выходных пакетов (packet), записанных SQL Сервером. |
@@pack_errors |
Указывает на число ошибок, которые возникли во время |
@@procid |
Содержит идентификатор выполняемой в данный момент |
@@rowcount |
Указывает на число строк, которые обрабатывались в |
@@servername |
Содержит название данного SQL Сервера. |
@@spid |
Указывает серверный идентификатор текущего процесса. |
@@sqlstatus |
Содержит информацию о состоянии, выданную последним |
@@textcolid |
Содержит идентификатор столбца, на который ссылается |
@@textdbid |
Указывает идентификатор базы данных, которая содержит |
@@textobjid |
Указывает идентификатор объекта, который содержит столбец, |
@@textptr |
Содержит текстовый указатель, который использовался при |
@@textsize |
Указывает на максимальное число байтов, которые можно |
@@textts |
Указывает на момент последнего обращения к текстовому |
@@tresh_hysteresis |
Указывает на минимально допустимую величину свободной |
@@timeticks |
Указывает длительность такта процессора в микросекундах. |
@@totalerrors |
Указывает на общее число ошибок, возникших в процессе |
@@total_read |
Указывает на число чтений с диска, которые SQL Сервер выполнил со |
@@total_write |
Указывает на число записей с диска, которые SQL Сервер выполнил со |
@@tranchained |
Указывает на текущий режим транзакций Transact—SQL программы. Значение этой |
@@trancount |
Указывает число активных транзакций текущего пользователя. |
@@transtate |
Указывает текущее состояние транзакции после выполнения |
@@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
[ << Назад ] [ Содержание ] [ Далее >> ]