【问题标题】:Using UNPIVOT with Dynamic SQL将 UNPIVOT 与动态 SQL 结合使用
【发布时间】:2013-06-01 01:22:13
【问题描述】:

我有一个具有此架构的表:

tbl结果

Question1 | Question2 | Question3 | etc | etc | Question240 |

在这些列中,值可以是以下:

1, 2, 3, 4, N, M

我需要像这样呈现数据:

| QuestionNumber | 1 | 2 | 3 | 4 | N | M |
------------------------------------------
| Question1      | 53| 27| 10| 5 | 2 | 3 |
| etc            | 20| 40| 32| 8 | 0 | 0 | <-- These values being % (but I can do the calculation later).
| etc            |

我需要能够控制结果集将输出多少行。我通过执行以下操作(仅 3 列)来做到这一点:

DECLARE @cname VARCHAR(MAX)
SELECT @cname = STUFF((
    SELECT ', ' + COLUMN_NAME
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE (TABLE_NAME = 'tblResults') AND (ORDINAL_POSITION BETWEEN 8 AND 10)
    FOR XML PATH(''), TYPE).value('.', 'varchar(max)'), 1,1,'')

DECLARE @sql NVARCHAR(MAX)
SET @sql = 'SELECT Answers, CASE WHEN Answer = '''' THEN ''N'' ELSE Answer END AS Answer, COUNT(Answer) AS Total
            FROM (
                SELECT '+@cname+'
                FROM tblResults
                WHERE (something = ''006'') AND (somethingElse = ''ABC'')
                ) AS MyTable
            UNPIVOT (Answer FOR Answers IN ('+@cname+')) AS MyUnPivot
            GROUP BY Answers, Answer
            ORDER BY Answers, Answer'

exec sp_executesql @sql

这会产生以下结果集:

| Answers | Answer | Total |
----------------------------
|Question1|    1   | 12474 |
|Question1|    2   | 188   |
|Question1|    3   | 200   |
|Question1|    4   | 5     |
|Question1|    N   | 0     |
|Question1|    M   | 142   |
|Question2|    1   | 14521 |
|etc      |        |       |
|etc      |        |       |

因此我的计划是使用动态 SQL,因为我想不出任何其他方法来做到这一点。我尝试了各种 UNPIVOT 方法,但似乎没有任何进展。

在有人提出这是多么糟糕的设计之前,我知道,这是我继承的东西,如果不重写第 3 方应用程序就无法更改它。

如果有人能想到更好的标题,请编辑。

谢谢。

【问题讨论】:

  • 你能发布一些额外的示例数据吗?什么正在成为新的列标题以及每个标题下的值是什么?
  • @bluefeet 我已经添加了到目前为止的内容,COUNT 是正确的,但我需要将 Answer 的值作为列。
  • 根据您当前查询产生的结果集,您希望最终结果是什么?
  • @bluefeet 看看我的问题中的第三个代码块,很抱歉造成混淆。列:QuestionNumber, 1, 2, 3, 4, N, M
  • 您显示的内容不清楚,您希望将 answer 值作为列标题。什么是一个问题有多个答案?你想要什么作为列标题?请详细说明,因为不是很清楚。您想要所有不同的答案作为新列吗?如果您有 1000 个不同的答案怎么办。

标签: sql sql-server-2005 pivot dynamic-sql unpivot


【解决方案1】:

根据您提供的信息,您需要将答案值 PIVOT 到列中。由于您的答案是一个静态值(1、2、3、4、N、M),因此您可以将这些值硬编码到您的查询中。

您仍然需要使用动态 SQL 来取消透视正确的列。代码将类似于以下内容:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @colsUnpivot = STUFF((SELECT distinct ','+ quotename(c.column_name)
                   from INFORMATION_SCHEMA.COLUMNS as C
                   where (TABLE_NAME = 'tblResults') and
                         (c.ORDINAL_POSITION BETWEEN 3 AND 5)
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query 
  = 'select questionNumber, [1], [2], [3], [4], [N], [M]
     from
     (
        select questionNumber, answer
        from
        (
          select '+@colsUnpivot+'
          from tblResults
        ) x
        unpivot
        (
          answer
          for questionNumber in ('+ @colsunpivot +')
        ) u
      ) d
      pivot
      (
        count(answer)
        for answer in ([1], [2], [3], [4], [N], [M])
      ) piv'

exec(@query);

SQL Fiddle with Demo。这给出了一个结果:

| QUESTIONNUMBER | 1 | 2 | 3 | 4 | N | M |
------------------------------------------
|      Question3 | 1 | 1 | 1 | 1 | 1 | 1 |
|      Question4 | 1 | 0 | 1 | 2 | 1 | 1 |
|      Question5 | 1 | 1 | 1 | 0 | 1 | 2 |

【讨论】:

  • 非常感谢,完美。您能解释一下 PIVOT 和 UNPIVOT,我之前使用过 UNPIVOT,但我不明白在这种情况下它是如何工作的,将两者一起使用。
  • @JackPettinger UNPIVOT 基本上是将您的数据从多列规范化为多行。将结果放入多行后,您希望将每个答案的总数显示为一列。 PIVOT 使用聚合函数count(),然后您提供要转换为列的值列表,这是您的答案列表。希望对您有所帮助,如果您有任何其他问题,请告诉我。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-30
  • 1970-01-01
  • 2016-01-22
  • 1970-01-01
相关资源
最近更新 更多