从 Dynamic SQL 调用存储过程或函数 - 使用可为 Null 的参数
Call a Stored Procedure or Function from Dynamic SQL - with Nullable Parameter
我正在尝试调用接受可为空参数的 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 接受可为 null 的参数。
这些示例来自 SQL 服务器。
存储过程和函数之间的答案实际上是不同的。
来自 Books On Line or whatever they call it this month(向下滚动一种方式):
When a parameter of the function has a default value, the keyword DEFAULT must be specified when the function is called to retrieve the default value. This behavior is different from using parameters with default values in stored procedures in which omitting the parameter also implies the default value. However, the DEFAULT keyword is not required when invoking a scalar function by using the EXECUTE statement.
所以对于一个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 );
只需使用显式文字 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)
您可能想要转义变量上可能存在的其他单引号,将其替换为双单引号,这样就不会破坏您的动态构建。
根据我的理解,我在 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
告诉我,你得到了什么。
我正在尝试调用接受可为空参数的 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 接受可为 null 的参数。 这些示例来自 SQL 服务器。
存储过程和函数之间的答案实际上是不同的。
来自 Books On Line or whatever they call it this month(向下滚动一种方式):
When a parameter of the function has a default value, the keyword DEFAULT must be specified when the function is called to retrieve the default value. This behavior is different from using parameters with default values in stored procedures in which omitting the parameter also implies the default value. However, the DEFAULT keyword is not required when invoking a scalar function by using the EXECUTE statement.
所以对于一个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 );
只需使用显式文字 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)
您可能想要转义变量上可能存在的其他单引号,将其替换为双单引号,这样就不会破坏您的动态构建。
根据我的理解,我在 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
告诉我,你得到了什么。