基于变量表和列名称将多行合并为单行的MS SQL存储过程

时间:2014-06-22 15:26:57

标签: sql sql-server sql-server-2008 stored-procedures

我正在使用MS SQL Server 2008.我正在尝试创建一个存储过程来将(可能)几行数据(答案)合并到目标表的单行中。这使用了答案表中的“table_name”字段和“column_name”字段。数据看起来像这样:

answers table
--------------
id int
table_name varchar
column_name varchar
answer_value varchar

因此,目标表(插入/更新)将来自'table_name'。来自anwsers的每一行都将填充目标表上的一列。

table_name_1 table
--------------
id int
column_name_1 varchar
column_name_2 varchar
column_name_3 varchar
etc...

请注意,可以在每个目标表上插入许多列(column_name_1 ... 2 ... 3)中的目标表(来自答案表的变量:table_name_1,table_name_2,table_name_3等)。

我想过使用WHILE语句循环遍历答案表。这可以构建一个变量,它将是目标表的插入/更新语句。然后以某种方式执行这些语句。我也注意到Merge看起来可能有助于解决这个问题(select / update / insert),但我的MS SQL存储过程体验非常少。有人可以建议这个问题的策略或解决方案吗?

Note 6/23/2014:我正在考虑使用单个Merge语句,但我不确定它是否可行。

2 个答案:

答案 0 :(得分:1)

我可能遗漏了一些东西,但解决问题的基本思路是使用元编程,就像动态旋转一样。
在这种特殊情况下,还有另一层使解决方案更加困难:结果需要在不同的执行中而不是分组。

可能解决方案的主干是

DECLARE @cols AS NVARCHAR(MAX)
DECLARE @query AS NVARCHAR(MAX)

--using a cursor on SELECT DISTINCT table_name FROM answers iterate:
--*Cursor Begin Here*
  --mock variable for the first value of the cursor
  DECLARE @table AS NVARCHAR(MAX) = 't1'

  -- Column list
  SELECT @cols = STUFF((SELECT distinct 
                               ',' + QUOTENAME(column_name)
                        FROM answers with (nolock)
                        WHERE table_name = @table
                        FOR XML PATH(''), TYPE
                       ).value('.', 'NVARCHAR(MAX)') 
                      , 1, 1, '')

  --Query definition
  SET @query = '
  SELECT ' + @cols + ' 
  INTO   ' + @table + '
  FROM   (SELECT column_name, answer_value 
          FROM   answers 
          WHERE  table_name = ''' + @table + ''') b
         PIVOT (MAX(answer_value) FOR column_name IN (' + @cols + ' )) p '

  --select @query

  EXEC sp_executesql @query

  --select to verify the execution
  --SELECT * FROM t1
--*Cursor End Here*

SQLFiddle Demo

省略了游标定义,因为我不确定它是否适用于SQLFiddle

除了动态数据透视表的模板之外,列表列表将按新表名称进行过滤,在查询定义中有SELECT ... INTO而不是SELECT

此脚本不考虑数据库中已存在的表,如果有可能将查询分为两部分:

  SET @query = '
  SELECT TOP 0 ' + @cols + ' 
  INTO   ' + @table + '
  FROM   (SELECT column_name, answer_value 
          FROM   answers 
          WHERE  table_name = ''' + @table + ''') b
         PIVOT (MAX(answer_value) FOR column_name IN (' + @cols + ' )) p '

创建没有数据的表(如果需要)和

  SET @query = '
  INSERT INTO   ' + @table + '(' + @cols + ')'
  SELECT ' + @cols + ' 
  FROM   (SELECT column_name, answer_value 
          FROM   answers 
          WHERE  table_name = ''' + @table + ''') b
         PIVOT (MAX(answer_value) FOR column_name IN (' + @cols + ' )) p '

MERGE插入/更新表格中的值 另一种可能性是DROP并重新创建每个表格。

答案 1 :(得分:0)

方法我解决了这个复杂的问题:

  • 创建多个临时表以处理您的数据
  • 选择并使用数据填充临时表
  • 使用动态旋转将行旋转为一行
  • 对多个表条目使用带有WHILE循环的CURSOR
  • 使用动态构建的MERGE语句设置@query
  • EXECUTE(@query)
  • 删除临时表