给出如下表,其中fn包含现有表值的函数的名称,param包含要传递给函数的param
fn | param
----------------
'fn_one' | 1001
'fn_two' | 1001
'fn_one' | 1002
'fn_two' | 1002
有没有办法通过使用基于集合的操作来获得这样的结果表? 结果表将包含第一个表中每一行的0- *行。
param | resultval
---------------------------
1001 | 'fn_one_result_a'
1001 | 'fn_one_result_b'
1001 | 'fn_two_result_one'
1002 | 'fn_two_result_one'
我以为我可以做一些像(伪)
的事情select t1.param, t2.resultval
from table1 t1
cross join exec sp_executesql('select * from '+t1.fn+'('+t1.param+')') t2
但是在exec sp_executesql中出现语法错误。
目前我们正在使用游标循环遍历第一个表并使用exec sp_executesql插入第二个表。虽然这可以正确地完成工作,但它也是经常使用的存储过程中最重的部分,我试图对其进行优化。对数据模型的更改可能意味着对应用程序的大部分核心进行了更改,而且只需在sql server上抛出硬件就会花费更多。
答案 0 :(得分:2)
您无法通过在SQL语句中引用其名称来访问对象。一种方法是使用case
语句:
select t1.*,
(case when fn = 'fn_one' then dbo.fn_one(t1.param)
when fn = 'fn_two' then dbo.fn_two(t1.param)
end) as resultval
from table1 t1 ;
有趣的是,您可以将case
封装为另一个函数,然后执行:
select t1.*, dbo.fn_generic(t1.fn, t1.param) as resultval
from table1 t1 ;
但是,在SQL Server中,您不能在用户定义的函数(在T-SQL中定义)中使用动态SQL,因此您仍然需要使用case
或类似的逻辑。
这些方法中的任何一种都可能比游标快得多,因为它们不需要发出多个查询。
答案 1 :(得分:2)
我相信这应该做你需要的,使用动态SQL生成一个语句,它可以为你提供结果,然后使用EXEC将它们放入你的表中。 FOR XML
技巧是将VARCHAR
值从多行连接在一起的常用技巧。它必须与AS [text()]
一起编写才能生效。
--=========================================================
-- Set up
--=========================================================
CREATE TABLE dbo.TestTableFunctions (function_name VARCHAR(50) NOT NULL, parameter VARCHAR(20) NOT NULL)
INSERT INTO dbo.TestTableFunctions (function_name, parameter)
VALUES ('fn_one', '1001'), ('fn_two', '1001'), ('fn_one', '1002'), ('fn_two', '1002')
CREATE TABLE dbo.TestTableFunctionsResults (function_name VARCHAR(50) NOT NULL, parameter VARCHAR(20) NOT NULL, result VARCHAR(200) NOT NULL)
GO
CREATE FUNCTION dbo.fn_one
(
@parameter VARCHAR(20)
)
RETURNS TABLE
AS
RETURN
SELECT 'fn_one_' + @parameter AS result
GO
CREATE FUNCTION dbo.fn_two
(
@parameter VARCHAR(20)
)
RETURNS TABLE
AS
RETURN
SELECT 'fn_two_' + @parameter AS result
GO
--=========================================================
-- The important stuff
--=========================================================
DECLARE @sql VARCHAR(MAX)
SELECT @sql =
(
SELECT 'SELECT ''' + T1.function_name + ''', ''' + T1.parameter + ''', F.result FROM ' + T1.function_name + '(' + T1.parameter + ') F UNION ALL ' AS [text()]
FROM
TestTableFunctions T1
FOR XML PATH ('')
)
SELECT @sql = SUBSTRING(@sql, 1, LEN(@sql) - 10)
INSERT INTO dbo.TestTableFunctionsResults
EXEC(@sql)
SELECT * FROM dbo.TestTableFunctionsResults
--=========================================================
-- Clean up
--=========================================================
DROP TABLE dbo.TestTableFunctions
DROP TABLE dbo.TestTableFunctionsResults
DROP FUNCTION dbo.fn_one
DROP FUNCTION dbo.fn_two
GO
第一个SELECT
语句(忽略设置)构建一个字符串,该字符串具有运行表中所有函数的语法,将结果全部UNION
一起返回。这样就可以使用EXEC
运行字符串,这意味着您可以INSERT
将这些结果放入您的表格中。
虽然有几个快速说明......首先,函数必须返回相同的结果集结构 - 具有相同数据类型的相同列数(从技术上讲,如果SQL Server可以,它们可能是不同的数据类型总是对它们进行隐式转换,但它确实不值得冒险)。其次,如果有人能够更新你的函数表,他们可以使用SQL注入来破坏你的系统。你需要严格控制它,我不会让用户只输入功能名称等。