Выполнить хранимую процедуру из функции - PullRequest
44 голосов
/ 14 июня 2011

Я знаю, что об этом просили до смерти, и я знаю, почему SQL Server не позволяет вам это сделать.

Но есть ли обходной путь для этого, кроме использования расширенных хранимых процедур?

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

Так что я действительно спрашиваю: есть ли ЛЮБОЙ способ запустить хранимую процедуру из функции?

EDIT:

Точка доказана: есть способ обойти это, но это так НЕПРАВИЛЬНО Я бы не стал этого делать. Я собираюсь изменить его на хранимую процедуру и выполнить в другом месте.

Ответы [ 5 ]

26 голосов
/ 14 июня 2011

РЕДАКТИРОВАТЬ: Я не пробовал это, поэтому я не могу ручаться за это!И вы уже знаете, что не должны этого делать, поэтому, пожалуйста, не делайте этого.НО ...

Попробуйте посмотреть здесь: http://sqlblog.com/blogs/denis_gobo/archive/2008/05/08/6703.aspx

Ключевой бит - это бит, который я попытался настроить для ваших целей:

DECLARE @SQL varchar(500)

SELECT @SQL = 'osql -S' +@@servername +' -E -q "exec dbName..sprocName "'

EXEC master..xp_cmdshell @SQL
11 голосов
/ 14 июня 2011

У функций не должно быть побочных эффектов, таких как изменение содержимого таблицы.

Хранимыми процедурами являются.

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


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

1 голос
/ 21 мая 2015

Другой вариант, помимо использования OPENQUERY и xp_cmdshell, заключается в использовании SQLCLR (функция SQL Server «Интеграция CLR»). Опция SQLCLR не только более безопасна, чем эти два других метода, но также есть потенциальная выгода от возможности вызова хранимой процедуры в текущем сеансе , так что она будет иметь доступ к любому основанному на сеансе объекты или настройки, такие как:

  • временные таблицы
  • временно хранимые процедуры
  • CONTEXT_INFO

Это может быть достигнуто с помощью "context connection = true;" как ConnectionString. Просто помните, что все другие ограничения, накладываемые на пользовательские функции T-SQL, будут применяться (то есть не может иметь побочных эффектов).

Если вы используете обычное соединение (т.е. не используете контекстное соединение), то оно будет работать как независимый вызов, так же, как и при использовании методов OPENQUERY и xp_cmdshell.

ОДНАКО , имейте в виду, что если вы будете использовать функцию, которая вызывает хранимую процедуру (независимо от того, какой из 3 отмеченных методов вы используете) в выражении, которое затрагивает более 1 строки, тогда нельзя ожидать, что поведение будет выполняться один раз в строке. Как упомянул @MartinSmith в комментарии к ответу @ MatBailie, Оптимизатор запросов не гарантирует ни времени, ни количества выполнений функций. Но если вы используете его в операторе SET @Variable = function(); или SELECT * FROM function();, тогда все должно быть в порядке.

Пример использования пользовательской функции .NET / C # SQLCLR для выполнения хранимой процедуры показан в следующей статье (которую я написал):

Лестница в SQLCLR Уровень 2. Образец хранимой процедуры и функции

0 голосов
/ 28 августа 2018

Я нашел решение этой проблемы. Мы можем построить функцию или представление с «визуализированным» sql в хранимой процедуре, которая затем может быть выполнена как обычно.

1.Создайте еще одного звездочку

CREATE PROCEDURE [dbo].[usp_FunctionBuilder]
DECLARE @outerSql VARCHAR(MAX)
DECLARE @innerSql VARCHAR(MAX)

2.Создайте динамический sql, который вы хотите выполнить в своей функции (Пример: вы можете использовать цикл и объединение, вы можете прочитать в другом sproc, использовать операторы if и параметры для условного sql и т. Д.)

SET @innerSql = 'your sql'

3. Оберните @innerSql в оператор создания функции и определите все внешние параметры, которые вы использовали в @innerSql, чтобы их можно было передать в сгенерированную функцию.

SET @outerSql = 'CREATE FUNCTION [dbo].[fn_GeneratedFunction] ( @Param varchar(10))
RETURNS TABLE
AS
RETURN
' + @innerSql;


EXEC(@outerSql)

Это просто псевдокод, но решение решает многие проблемы, такие как ограничения связанного сервера, параметры, динамический sql в функции, динамическое имя сервера / базы данных / таблицы, циклы и т. Д.

Вам нужно будет настроить его под свои нужды, (пример: изменение возврата в функции)

0 голосов
/ 26 июня 2014

Вот еще один возможный обходной путь:

if exists (select * from master..sysservers where srvname = 'loopback')
    exec sp_dropserver 'loopback'
go
exec sp_addlinkedserver @server = N'loopback', @srvproduct = N'', @provider = N'SQLOLEDB', @datasrc = @@servername
go

create function testit()
    returns int
as
begin
    declare @res int;
    select @res=count(*) from openquery(loopback, 'exec sp_who');
    return @res
end
go

select dbo.testit()

Это не так страшно, как xp_cmdshell, но также имеет слишком много последствий для практического использования.

...