Вызов хранимой процедуры или функции из динамического SQL - с параметром Nullable - PullRequest
0 голосов
/ 18 декабря 2018

Я пытаюсь вызвать функцию sql, принимающую обнуляемый параметр - из оператора динамического SQL .

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

SET dynamicQuery = 
   'select * from [qlik].udf_getStatistic( ''' + @myParameter + ''' )'

Пример выше находится внутри хранимой процедуры, которой передается @myParameter.Это может быть ноль или строковое значение.Ясно, что когда это строка, она должна быть заключена в кавычки, но когда она пуста, она не должна быть заключена в кавычки.Следующее:

select * from [qlik].udf_getStatistic( 'Heights' )

select * from [qlik].udf_getStatistic( NULL )

Вопрос в равной степени применим к вызову хранимой процедуры , принимающей обнуляемый параметр из динамического SQL.Примеры взяты из SQL Server.

Ответы [ 3 ]

0 голосов
/ 18 декабря 2018

Просто экранируйте значение NULL с явным литералом NULL, следя за тем, чтобы кавычки включались только тогда, когда значение не NULL.

DECLARE @myParameter VARCHAR(10) = 'ABC'

DECLARE @dynamicQuery VARCHAR(MAX)

SET @dynamicQuery = 
   'select * from [qlik].udf_getStatistic(' + ISNULL('''' + @myParameter + '''', 'NULL') + ')'


SELECT @dynamicQuery -- select * from [qlik].udf_getStatistic('ABC')

SET @myParameter = NULL

SET @dynamicQuery = 
   'select * from [qlik].udf_getStatistic(' + ISNULL('''' + @myParameter + '''', 'NULL') + ')'

SELECT @dynamicQuery -- select * from [qlik].udf_getStatistic(NULL)

Возможно, вы захотите экранировать дополнительныеодинарные кавычки, которые могут быть в вашей переменной, заменяя их двойными одинарными кавычками, чтобы не нарушить динамическую сборку.

0 голосов
/ 20 декабря 2018

Насколько я понимаю, я пробую это на SQL Server 2012,

CREATE PROCEDURE ToNullProc 
     (@i VARCHAR(20)) 
AS 
BEGIN
    PRINT 'you entered ' + @i
END

CREATE FUNCTION ToNullFun 
     (@i VARCHAR(20)) 
RETURNS @table TABLE (i VARCHAR(20))
AS
BEGIN
    INSERT INTO @table 
        SELECT ('You entered ' + @i) a
    RETURN
END

DECLARE @j VARCHAR(20) = 'Hi',
        @QueryFun NVARCHAR(50) = N'',
        @QueryProd NVARCHAR(50) = N''

IF @j IS NOT NULL
BEGIN
    SET @QueryFun = N'select * from ToNullFun ('''+@j+''')'
    SET @QueryProd = N'exec ToNullProc '''+@j+''''
END
ELSE BEGIN
   SET @QueryFun = N'select * from ToNullFun ('+@j+')'
   SET @QueryProd = N'exec ToNullProc '+@j+''
END

PRINT @queryfun
PRINT @queryprod

EXEC sp_executesql @queryfun
EXEC sp_executesql @queryprod

Обновление для динамической процедуры и динамической функции :

create table #temp (Num int identity (1,1), NullVal int)
insert into #temp (NullVal) values (1),(null),(3)

alter proc ToNullProc (
 @Operator varchar (max), @NullVal varchar (max)
) as
begin 

 declare @Query nvarchar (max) = N'select * from #temp where NullVal ' + 
  @Operator + @NullVal 
 -- print @query + ' ToNullProc print '

 exec sp_executesql @query  -- Here we run the select query from Proc

end

create function ToNullFun (
 @Operator varchar (max), @NullVal varchar (max)
) 
returns nvarchar (max)
as
begin    
 declare @Query nvarchar (max)

 set @Query = N'select * from #temp where NullVal ' + @Operator + @NullVal 

 /* 
  I try to into to Table variable by using ITVF,
  'insert into @table exec sp_executesql @query'.
  But this type of insert is not allowed in ITVF.
*/

 return @query

end

declare @NullVal varchar (max) = '1'
, @QueryFun nvarchar (max) = N''
, @QueryProd nvarchar (max) = N''
declare @FunResultTalbe table (
 Query nvarchar (100)
) /* To store the result Funtion */
if @NullVal is not null
begin
 set @QueryFun = N'select dbo.ToNullFun ('' = '','''+@NullVal+''')'
 set @QueryProd = N'exec ToNullProc '' = '','''+@NullVal+''''
end
else begin 
 set @QueryFun = N'select dbo.ToNullFun ('' is null '','''')'
 set @QueryProd = N'exec ToNullProc '' is null '','''''
end

print  @queryfun + ' At start'
print  @queryprod + ' At start'

exec sp_executesql @queryprod  -- It calls Proc 

insert into @FunResultTalbe
exec sp_executesql @queryfun   -- It calls the Function and insert the query into the table.

set @QueryFun = (select top 1 * from @FunResultTalbe)  -- Here we get the query from the table.
print @queryfun

exec sp_executesql @queryfun  -- Here we run the select query. Which is dynamic

Наборы результатов

-- Result of Procedure
Num NullVal
1   1

-- Result of Function
Num NullVal
1   1

Дайте мне знать, что вы получили.

0 голосов
/ 18 декабря 2018

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

С Books On Line или как там ее называют в этом месяце (Прокрутить вниз):

Когда параметр функции имеет значение по умолчанию,ключевое слово DEFAULT должно быть указано при вызове функции для получения значения по умолчанию.Это поведение отличается от использования параметров со значениями по умолчанию в хранимых процедурах, в которых пропуск параметра также подразумевает значение по умолчанию.Однако ключевое слово DEFAULT не требуется при вызове скалярной функции с помощью оператора EXECUTE.

Так что для процедуры, когда вы хотите передать параметр NULL, вы можете просто не передавать его,Для функции, однако, вы должны указать ей явно использовать значение DEFAULT.В любом случае, вы не передаете это явно NULL.К счастью для вашего динамического SQL, явный DEFAULT также работает с хранимой процедурой.В обоих случаях, чтобы убедиться, что параметры, которые вы передаете , правильно назначены, вы хотите использовать явные имена параметров в вашем вызове.

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

CREATE FUNCTION (or procedure) [qlik].udf_getStatistic (
  @param1 integer = 0,
  @param2 varchar(100) = 'foo'
) AS ...

Оба параметра являются необязательными.Поскольку это функция, этот вызов выдаст ошибку insufficient number of parameters:

select * from [qlik].udf_getStatistic( 'Heights' );

Если бы это был вызов процедуры, он бы выдал cannot convert value 'Heights' to data type integer, потому что он будет применять единственное значение параметра, переданное впервый встреченный параметр, который ожидает целое число.В обоих случаях вы получаете то, что вам нужно, таким образом:

select * from [qlik].udf_getStatistic( @param1 = DEFAULT, @param2 = 'Heights' );

, что приводит нас к вашему динамическому SQL.Добавьте ваши имена параметров к статическому тексту, затем используйте COALESCE (или CASE, если хотите), чтобы решить, передавать ли явное значение или вызов DEFAULT.

DECLARE @myParameter1 VARCHAR(100) = 'foo',
        @myParameter2 INTEGER,
        @SQL NVARCHAR(MAX);


SET @SQL = 
   'select 
      * 
    from [qlik].udf_getStatistic( 
      @param1 = ''' + COALESCE(@myParameter1, 'DEFAULT') + ''', 
      @param2 = ' + COALESCE(CAST(@myParameter2 AS VARCHAR(30)),'DEFAULT') + ' );';

SELECT @SQL;

Результат:

select * from [qlik].udf_getStatistic( @param1 = 'foo', @param2 = DEFAULT );
...