まず最初に、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
-- ====================================================================