首先,您必须了解 SQL Server 拒绝在函数中允许动态 SQL 的事实。这很不幸,但这是您必须解决的限制。
这是一种在表的每一行上应用动态 SQL 逻辑的技术
- 创建一个临时表来保存动态 SQL 的所有输入参数以及预期结果
- 创建一个已经期望临时表存在的存储过程,并循环应用动态 SQL 逻辑的临时表的行
- 将要评估的数据添加到临时表
- 执行你的动态 SQL 过程
- 享受您的预期结果:-)
1)让我们从设置一些测试数据开始。
-- ====================================================================
-- BEGIN: Setup test data
-- ====================================================================
IF OBJECT_ID('Branch', 'U') IS NOT NULL DROP TABLE Branch;
IF OBJECT_ID('Branch2', 'U') IS NOT NULL DROP TABLE Branch2;
GO
CREATE TABLE Branch (
ID int
,Column1 varchar(20)
,Column2 varchar(20)
,Column3 varchar(20)
)
CREATE TABLE Branch2 (
ID int
,Column1 varchar(20)
,Column2 varchar(20)
,Column3 varchar(20)
)
SET NOCOUNT ON
INSERT Branch SELECT 1, 'Hello', 'World', 'I write SQL'
INSERT Branch SELECT 2, 'I like', 'it to be', 'complicated'
INSERT Branch2 SELECT 1, 'Hello', 'World', 'I write SQL'
INSERT Branch2 SELECT 2, 'I like', 'it to be', 'complicated'
SET NOCOUNT OFF
GO
-- ====================================================================
-- END: Setup test data
-- ====================================================================
2) 接下来,我们将创建一个处理动态 SQL 的 proc。
-- ====================================================================
-- BEGIN: Proc with dynamic SQL logic
-- ====================================================================
IF OBJECT_ID('prcReturnTableData', 'P') IS NOT NULL DROP PROCEDURE prcReturnTableData;
GO
CREATE PROCEDURE prcReturnTableData
AS
DECLARE @SQL nvarchar(MAX)
,@ParameterDefinitions nvarchar(MAX)
,@TableName varchar(128)
,@ID int
SELECT @ParameterDefinitions = '@ID int'
DECLARE @idx int
SELECT @idx = MIN(idx) FROM #Result
WHILE @idx IS NOT NULL
BEGIN
SELECT @TableName = TableName
,@ID = ID
FROM #Result
WHERE idx = @idx
SELECT @SQL = '
DECLARE @ReturnVal varchar(MAX)
SELECT @ReturnVal = ''''
SELECT @ReturnVal = @ReturnVal
+ '' // ''
+ T2.N.value(''local-name(.)'', ''nvarchar(128)'')
+ '': ''
+ T2.N.value(''.'', ''nvarchar(max)'')
FROM (
SELECT *
FROM ' + @TableName + '
WHERE ID = @ID
FOR XML PATH(''''), type
) as T1(X)
CROSS APPLY T1.X.nodes(''/*'') as T2(N)
UPDATE #Result SET ReturnVal = @ReturnVal WHERE ID = @ID';
EXEC sp_executeSQL @SQL, @ParameterDefinitions, @ID = @ID;
SELECT @idx = MIN(idx) FROM #Result WHERE idx > @idx
END
GO
-- ====================================================================
-- END: Proc with dynamic SQL logic
-- ====================================================================
3)最后,让我们执行proc,得到我们想要的结果。
-- ====================================================================
-- BEGIN: Solution to execute dynamic SQL logic on each row of a table
-- ====================================================================
-- Create the temp table that the dynamic SQL proc expects
IF OBJECT_ID('tempdb..#Result', 'U') IS NOT NULL DROP TABLE #Result;
CREATE TABLE #Result (idx int IDENTITY(1,1), TableName varchar(128) NOT NULL, ID int NOT NULL, ReturnVal varchar(MAX) NULL);
-- Popluate the temp table with the rows you want to evaluate
INSERT #Result (TableName, ID)
SELECT 'Branch', ID FROM Branch
INSERT #Result (TableName, ID)
SELECT 'Branch2', ID FROM Branch2
-- Results before
SELECT * FROM #Result
-- Execute the dynamic SQL proc
EXEC prcReturnTableData
-- Results after
SELECT * FROM #Result
-- ====================================================================
-- END: Solution to execute dynamic SQL logic on each row of a table
-- ====================================================================