Sql server 完全动态调用SQL存储过程的方法(sp_executesql中的动态参数)?

Sql server 完全动态调用SQL存储过程的方法(sp_executesql中的动态参数)?,sql-server,ssms,Sql Server,Ssms,例如,当从外部语言c调用SQL Server存储过程时,调用的编码方式是,给定的存储过程可以完全用元数据描述,并使用泛型函数调用。调用命令对象上的参数集合有助于在不同过程之间支持不同数量的参数 如果希望完全在SQL Server中实现类似的功能,如果使用一个相关的示例,可以在此处找到:……您可以在那里获得大部分方法,但主要问题是函数调用中的参数必须是硬编码的 文章中的示例: EXEC sp_executesql @sql, @paramlist,

例如,当从外部语言c调用SQL Server存储过程时,调用的编码方式是,给定的存储过程可以完全用元数据描述,并使用泛型函数调用。调用命令对象上的参数集合有助于在不同过程之间支持不同数量的参数

如果希望完全在SQL Server中实现类似的功能,如果使用一个相关的示例,可以在此处找到:……您可以在那里获得大部分方法,但主要问题是函数调用中的参数必须是硬编码的

文章中的示例:

EXEC sp_executesql @sql, @paramlist,                               
               @orderid, @fromdate, @todate, @minprice,        
               @maxprice,  @custid, @custname, @city, @region, 
               @country, @prodid, @prodname   
在本例中,SQL语句存储在@SQL中,参数列表存储在@paramList中,下面是实际参数的列表

@sql和@paramList都是简单的nvarchar变量,可以通过从元数据读取并分配给变量来编程设置,但实际参数本身是硬编码的

因此,问题是:


有没有办法指定实际参数和值,使整个函数的实现完全通用?

参数列表可以作为逗号分隔或特殊字符分隔的列表发送,然后可以将列表解析到表中。 在本例中,我使用了and=

这是我最初的解决方案:

DECLARE @List VARCHAR(MAX) = 'a=1,b=3,c=hey,d=12/05/10,val5='
DECLARE @Delimiter1 VARCHAR(1) = ','
DECLARE @Delimiter2 VARCHAR(1) = '='
----
SELECT y.i.value('(./text())[1]', 'nvarchar(4000)') pass1
INTO #Buffer
FROM ( 
    SELECT x = CONVERT(XML, '<i>' 
        + REPLACE(@List, @Delimiter1, '</i><i>') 
        + '</i>').query('.')
) a 
CROSS APPLY x.nodes('i') y(i)

SELECT ROW_NUMBER()OVER(ORDER BY(SELECT 1)) rn,y.i.value('(./text())[1]', 'nvarchar(4000)') pass2
INTO #PreResult
FROM ( 
    SELECT x = CONVERT(XML, '<i>' 
        + REPLACE(b.pass1, @Delimiter2, '</i><i>') 
        + '</i>').query('.')
    FROM #Buffer b
    WHERE b.pass1 LIKE '%=%' AND b.pass1 NOT LIKE '%=%=%' -- to make sure assignment has place and there is no double or more assignments
) a 
CROSS APPLY x.nodes('i') y(i)

SELECT @List '@List'
--SELECT '' '#Buffer',* FROM #Buffer b
--SELECT '' '#PreResult',* FROM #PreResult p

SELECT p.pass2 [Variable],p2.pass2 [Value]
FROM #PreResult p
INNER JOIN #PreResult p2 ON p2.rn = p.rn + 1
WHERE p.rn%2 > 0

DROP TABLE #Buffer
DROP TABLE #PreResult
更聪明的是:

DECLARE @List VARCHAR(MAX) = 'a=1,b=3,c=hey,d=12/05/10,val5='

DECLARE @Delimiter1 VARCHAR(1) = ','
DECLARE @Delimiter2 VARCHAR(1) = '='

SELECT v.v.value('(./text())[1]', 'nvarchar(4000)') [Variable],n.n.value('(./text())[1]', 'nvarchar(4000)') [Value]
FROM ( 
    SELECT x = CONVERT(XML, 
        '<a><v>' + REPLACE(REPLACE(@List,@Delimiter1,'</n></a><a><v>'),@Delimiter2,'</v><n>') + '</n></a>'
    ).query('.')
) a 
CROSS APPLY x.nodes('a') y(a)
CROSS APPLY y.a.nodes('v') v(v)
CROSS APPLY y.a.nodes('n') n(n)
最好的方法是发送带有参数列表的XML,然后将该XML解析到表中

如果你有任何问题,请告诉我

更新: 因此,这里只需要提供一个值—参数及其值的列表。 在查询中,您可以对它们执行任何操作

DECLARE @sql NVARCHAR(MAX),@paramlist NVARCHAR(MAX)

SET @sql = N'
DECLARE @Delimiter1 VARCHAR(1) = '',''
DECLARE @Delimiter2 VARCHAR(1) = ''=''

SELECT v.v.value(''(./text())[1]'', ''NVARCHAR(4000)'') [Variable],n.n.value(''(./text())[1]'', ''NVARCHAR(4000)'') [Value]
INTO #Values
FROM ( 
    SELECT x = CONVERT(XML, 
        ''<a><v>'' + REPLACE(REPLACE(@List,@Delimiter1,''</n></a><a><v>''),@Delimiter2,''</v><n>'') + ''</n></a>''
    ).query(''.'')
) a 
CROSS APPLY x.nodes(''a'') y(a)
CROSS APPLY y.a.nodes(''v'') v(v)
CROSS APPLY y.a.nodes(''n'') n(n)

/*Do whatever you want with the values*/
/*There even could be a stored proc call based on parameters provided*/
SELECT v.Value FROM #Values v WHERE v.Variable = ''c''


DROP TABLE #Values
'
SET @paramlist = '@list nvarchar(max)'

DECLARE @List VARCHAR(MAX) = 'a=1,b=3,c=hey,d=12/05/10,val5='

EXEC sp_executesql @sql, @paramlist, @list=@List

这是可以做到的,但我还不知道是否有性能方面的影响,而且有些方法对sql注入是开放的

下面的第二个问题中显示了一些示例,具体询问了使用不同语法的性能,其中一些语法有助于纯动态SQL,其他语法则没有:


但这并不重要;我无法解决调用EXEC sp_executesql而不必显式传递每个参数值的问题,或者我遗漏了什么?或者我遗漏了要点。您能否提供更具体的示例,说明您正试图向SQL发送什么,以及接下来应该发生什么,即需要如何处理值?下面的问题: