ネタ元:別テーブルの値で文字列を置換えしてUPDATE - Database Expert会議室
ネタ元で スカラ値関数 を使ったクエリを載せた理由は、再帰で実装したクエリを誰かが載せてくれたらいいなぁ〜という淡い期待からです。
ただ、そのままクローズした様なので、自分で調べてみました。
遠い昔に ORACLE で再帰クエリを書いた記憶はあるんですが、SQL Server だと無かったので初チャレンジ!
※ORACLE と書き方が違うんですね〜、CONNECT BY 〜 を使った気がする。
SQL SERVER で 再帰クエリを使うには、ここらへんが参考になりそうです。
共通テーブル式を使用する再帰クエリ
WITH common_table_expression (Transact-SQL)
WITH が追加されたのは知ってたんですが(使った事無いけど)、これで再帰を実現するようです。
CREATE TABLE [dbo].[Table_1]( [id] [int] IDENTITY(1,1) NOT NULL, [val] [nvarchar](max) NOT NULL ) ON [PRIMARY] GO SET IDENTITY_INSERT [dbo].[Table_1] ON INSERT [dbo].[Table_1] ([id], [val]) VALUES (1, N'abcdefghij') INSERT [dbo].[Table_1] ([id], [val]) VALUES (2, N'agnrfmlmn') SET IDENTITY_INSERT [dbo].[Table_1] OFF GO CREATE TABLE [dbo].[Table_2]( [mae] [nvarchar](1) NOT NULL, [ato] [nvarchar](1) NOT NULL ) ON [PRIMARY] GO INSERT [dbo].[Table_2] ([mae], [ato]) VALUES (N'a', N'b') INSERT [dbo].[Table_2] ([mae], [ato]) VALUES (N'b', N'c') INSERT [dbo].[Table_2] ([mae], [ato]) VALUES (N'c', N'd') INSERT [dbo].[Table_2] ([mae], [ato]) VALUES (N'd', N'e') INSERT [dbo].[Table_2] ([mae], [ato]) VALUES (N'e', N'f') INSERT [dbo].[Table_2] ([mae], [ato]) VALUES (N'f', N'g') GO -- ここまでがテーブルとデータ作成部分 SELECT * FROM [Table_1] BEGIN TRAN; WITH [CTE] ([id], [repVal], [currentNum]) AS ( SELECT [Table_1].[id], REPLACE([Table_1].[val], [一行取得].[mae], [一行取得].[ato]) AS [repVal], [一行取得].[currentNum] FROM [Table_1], ( SELECT [mae], [ato], [ROWNUM], MIN([ROWNUM]) AS [currentNum] FROM ( SELECT [mae], [ato], ROW_NUMBER () OVER (ORDER BY [mae]) AS [ROWNUM] FROM [Table_2] ) AS [TMP] WHERE [ROWNUM] = 1 GROUP BY [mae], [ato], [ROWNUM] ) AS [一行取得] UNION ALL SELECT [CTE].[id], REPLACE([CTE].[repVal], A.[mae], A.[ato]) AS [repVal], [CTE].[currentNum] + 1 AS [currentNum] FROM ( SELECT [mae], [ato], ROW_NUMBER () OVER (ORDER BY [mae]) AS [ROWNUM] FROM [Table_2] ) AS A INNER JOIN [CTE] ON ( [CTE].[currentNum] + 1 = A.[ROWNUM] ) ) UPDATE [Table_1] SET [val] = ( SELECT TOP 1 [repVal] FROM [CTE] WHERE [CTE].[id] = [Table_1].[id] ORDER BY [currentNum] DESC ) SELECT * FROM [Table_1] ROLLBACK GO DROP TABLE [Table_2] DROP TABLE [Table_1] GO
最適かどうかは分かりませんが、ネタ元に貼り付けた スカラ値関数 を使ったクエリと同じ結果になりますね。
しかし、「こうすれば実現出来る!」っていう発想が出てくるのが凄いなぁ。再帰で UPDATE っていう発想が無かった。
再帰SQL のイメージって 階層構造 を取得する*1位しか思いつかない。勉強になりました。
*1:SQL SERVER 2008 から Hierarchyid 型が追加されているので、再帰する必要が無くなったはず。これも使った事無い…