Функции vs Хранимые процедуры в SQL Server

Функции vs Хранимые процедуры в SQL Server


Введение

Обычно администраторы баз данных предпочитают хранимые процедуры вместо функций в SQL Server. Хорошая ли это практика?

В этой статье мы расскажем, как создавать хранимые процедуры и функции в SQL Server, и покажем преимущества и недостатки каждой из них. В наших примерах мы будем использовать скалярные функции, определяемые пользователем, или UDF. В дальнейшем мы покажем некоторые функции, возвращающие таблицы. Функции CLR здесь рассматриваться не будут.

Мы рассмотрим следующие темы:

  1. Создание Hello World в хранимой процедуре и в функции
  2. Вызов хранимой процедуры и вызов функции
  3. Использование переменных в хранимой процедуре и функции
  4. Возможность повторного использования
  5. Вызов функций/процедур внутри функций/процедур

Начинаем

  1. Создание Hello World в хранимой процедуре и в функции

Давайте создадим "Hello world" в хранимой процедуре и функции, чтобы проверить, какую из них легче создать.

Сначала мы создадим простую хранимую процедуру с помощью оператора print в SSMS:

CREATE PROCEDURE HelloWorldprocedure
AS
PRINT 'Hello World'

Выполните код, а затем вызовите хранимую процедуру в SQL:

exec HelloWorldprocedure

Выполнив код, вы увидите сообщение "Hello World":

Рисунок 1. Результат хранимой процедуры "Hello world"

Теперь попробуем сделать то же самое с функцией:

CREATE FUNCTION dbo.helloworldfunction()
RETURNS varchar(20)
AS 
BEGIN
  RETURN 'Hello world'
END

Мы можем вызвать функцию с помощью SELECT.

Функция вернет следующее:

Рисунок 2. "Hello world" с использованием функции

Если сравнить код, то функция требует больше кода для выполнения одного и того же действия. Блоки BEGIN и END являются обязательными в функции, в то время как хранимая процедура не требует их, если она состоит всего из одной строки. В функции обязательно использование аргументов RETURNS и RETURN, в то время как в хранимой процедуре это не обязательно.

В двух словах, хранимая процедура является более гибкой для написания нужного кода, в то время как функции имеют жесткую структуру и функциональность.


2. Вызов хранимой процедуры и вызов функции

Хранимую процедуру можно вызывать разными способами:

exec HelloWorldprocedure
execute HelloWorldprocedure
execute dbo.HelloWorldprocedure
HelloWorldprocedure

Можно вызвать с помощью exec или execute, и даже можно вызвать хранимую процедуру без оператора execute. При этом не обязательно указывать имя схемы.

Функции менее гибкие. Для их вызова необходимо указать схему (это хорошая практика, чтобы избежать конфликтов с другими объектами с тем же именем и другой схемой).

Давайте вызовем функцию без указания схемы:

select helloworldfunction() as regards

На экране появится следующее сообщение:

Msg 195, Level 15, State 10, Line 20 ‘helloworldfunction’ is not a recognized built-in function name

Как вы видите, имя схемы является обязательным для вызова функции:

select dbo.helloworldfunction() as regards

3. Использование переменных в хранимой процедуре и функции

Давайте преобразуем градусы Цельсия в градусы Фаренгейта с помощью хранимых процедур и функций, чтобы увидеть различия. Начнем с хранимой процедуры:

CREATE PROCEDURE CONVERTCELSIUSTOFAHRENHEIT
@celsius real
as
select @celsius*1.8+32 as Fahrenheit

Цельсий является входным параметром, и мы выполняем вычисления в операторе select для преобразования в градусы Фаренгейта.

Если мы вызовем хранимую процедуру, мы получим в результате преобразованный 0°C:

exec CONVERTCELSIUSTOFAHRENHEIT 0

Результат будет равен 32 °F:

Рисунок 3. Хранимая процедура в SQL для преобразования Цельсия в Фаренгейт

Давайте попробуем сделать то же самое с функцией:

CREATE FUNCTION dbo.f_celsiustofahrenheit(@celcius real)
RETURNS real
AS 
BEGIN
 RETURN  @celcius*1.8+32
END

Вы можете вызвать созданную функцию следующим образом:

select dbo.f_celsiustofahrenheit(0) as fahrenheit

Мы конвертируем 0 °C в °F. Как видите, код очень прост в обоих случаях.


4. Возможность повторного использования

Главное преимущество функции заключается в том, что ее можно повторно использовать в коде. Например, вы можете сделать следующее:

select CONCAT(dbo.helloworldfunction(),', welcome to sqlshack') Regards

В этом примере мы объединяем функцию из примера 1 со строкой. В результате получается следующее:

Рисунок 4. Объединение строки в функцию

Как видите, вы можете легко объединить функцию со строкой. Чтобы сделать нечто подобное с хранимой процедурой в SQL, нам понадобится выходная переменная (output variable) в хранимой процедуре для объединения такой переменной со строкой. Давайте посмотрим на хранимую процедуру:

create procedure outputparam
@paramout varchar(20) out
as
select @paramout='Hello world'

Эта процедура назначает строку Hello Word выходному параметру. Вы можете использовать слово out или output.

Код может показаться простым, но вызов процедуры для использования выходного параметра для конкатенации немного сложнее, чем функция:

declare @message varchar(20)
exec outputparam @paramout=@message out
select @message as regards
select CONCAT(@message,', welcome to sqlshack')

Как вы видите, необходимо объявить новую переменную с именем @message или любым другим именем по вашему усмотрению. Когда вы вызываете хранимую процедуру, вам нужно указать, что это выходной параметр. Преимуществом хранимых процедур является то, что вы можете иметь несколько параметров, в то время как в функциях вы можете вернуть только одну переменную (скалярная функция) или одну таблицу (таблично-значные функции).


5. Вызов функций/процедур внутри функций/процедур

Можем ли мы вызывать хранимые процедуры внутри функции?

Давайте посмотрим:

CREATE FUNCTION dbo.procedureinsidefunction()
RETURNS varchar(22)
AS 
BEGIN
 execute HelloWorldprocedure
 Declare @hellovar varchar(22)=', welcome to sqlshack'
 RETURN  @hellovar 
END

Функция будет вызывать процедуру HelloWorld, созданную в разделе 1.

Если мы вызовем функцию, то получим следующее сообщение:

Msg 557, Level 16, State 2, Line 65 Only functions and some extended stored procedures can be executed from within a function.

Как вы видите, вы не можете вызвать функцию из хранимой процедуры. Можете ли вы вызвать функцию из процедуры?

Здесь используется процедура:

END
create procedure functioninsideprocedure
select dbo.helloworldfunction()

Если мы вызовем хранимую процедуру в SQL, мы сможем проверить, работает она или нет:

exec functioninsideprocedure

Результат отображается следующим образом:

Рисунок 5. Функция внутри процедуры

Как вы видите, вы можете вызывать функции внутри хранимой процедуры и не можете вызывать хранимую процедуру внутри функции.

Вы можете вызывать функцию внутри функции. В следующем коде показан простой пример:

CREATE FUNCTION dbo.functioninsidefunction()
RETURNS varchar(50)
AS 
BEGIN
 RETURN  dbo.helloworldfunction()
END

Мы можем вызвать функцию как обычно:

select dbo.functioninsidefunction() as regards

Можно ли вызывать процедуры внутри других процедур?

Да, можно. Вот пример на эту тему:

create procedure procedureinsideprocedure
as
execute dbo.HelloWorldprocedure

Вы можете запускать процедуру как обычно:

 exec dbo.procedureinsideprocedure


Выводы

Хранимые процедуры в SQL проще создавать, а функции имеют более жесткую структуру и поддерживают меньше функциональности. С другой стороны, вы можете легко использовать результаты работы функции в T-SQL. Мы показали, как объединить функцию со строкой. Манипулировать результатами хранимой процедуры сложнее.

В рамках скалярной функции вы можете вернуть только одну переменную, а в хранимой процедуре - несколько. Однако, чтобы вызвать выходные переменные в хранимой процедуре, необходимо объявить переменные вне процедуры для ее вызова.

Кроме того, вы не можете вызывать процедуры внутри функции. С другой стороны, в процедуре можно вызывать функции и хранимые процедуры.

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


 

Оригинал статьи: https://www.sqlshack.com/functions-vs-stored-procedures-sql-server/#:~:text=In%20a%20function%2C%20it%20is,a%20rigid%20structure%20and%20functionality.



Report Page