从动态SQL调用存储过程或函数-具有可空参数

时间:2018-12-18 11:28:14

标签: sql-server stored-procedures parameter-passing dynamic-sql sql-function

我正在尝试调用一个接受可空参数的sql函数-从动态SQL语句

创建动态语句很困难,因为当参数值为'NULL'时,合并会使整个语句为空。我有以下内容:

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

上面的示例在@myParameter传递到的存储过程中。它可以为null或字符串值。显然,当它是一个字符串时,需要用引号引起来,但当它为null时,一定不能用引号引起来。如下:

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

select * from [qlik].udf_getStatistic( NULL )

这个问题同样适用于调用存储过程,该存储过程接受来自动态SQL的可为空的参数。 这些示例来自SQL Server。

3 个答案:

答案 0 :(得分:1)

答案实际上在存储过程和函数之间是不同的。

Books On Line or whatever they call it this month(向下滚动):

  

当函数的参数具有默认值时,在调用函数以检索默认值时必须指定关键字DEFAULT。此行为与在存储过程中使用具有默认值的参数不同,在存储过程中,省略参数也表示默认值。但是,使用EXECUTE语句调用标量函数时,不需要DEFAULT关键字。

因此对于proc,当您想传递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 );

答案 1 :(得分:1)

只需使用显式文字from . import views from django.conf.urls import url urlpatterns = [ url(r'^$', views.blog_view, name='blog_view'), ] 来对NULL值进行转义,请确保仅在值不为NULL时才包括引号。

NULL

您可能希望转义变量中可能包含的其他单引号,将其替换为双单引号,以免破坏动态构建。

答案 2 :(得分:1)

据我了解,我在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

让我知道,你得到了什么。