如何在动态查询中将行值连接到列名

Posted

技术标签:

【中文标题】如何在动态查询中将行值连接到列名【英文标题】:How to join row values to column names in a dynamic query 【发布时间】:2013-04-04 14:09:04 【问题描述】:

我正在开发一个允许配置问题和答案的应用程序。目前最多可以有 20 个答案,但可能更少。

我的结构如下:

问题

+----+--------+--------------+-------------+
| ID | FormId | QuestionText | AnswerField |
+----+--------+--------------+-------------+
|  1 |      1 | Name         | Answer01    |
|  2 |      1 | Address      | Answer02    |
|  3 |      1 | Phone        | Answer03    |
|  4 |      1 | Email        | Answer04    |
|  5 |      2 | First Name   | Answer01    |
|  6 |      2 | Surname      | Answer02    |
+----+--------+--------------+-------------+

答案

+----+--------+----------+------------+--------------+--------------+----------------+----------+----------+
| ID | FormId | RecordId |  Answer01  |   Answer02   |   Answer03   |    Answer04    | Answer05 | Answer06 |
+----+--------+----------+------------+--------------+--------------+----------------+----------+----------+
|  1 |      1 |        1 | Bob Smith  | Bobs Address | 01234 111222 | bob@smith.com  | Null     | Null     |
|  2 |      1 |        2 | Joe Bloggs | Joes Address | 04321 333444 | joe@bloggs.com | Null     | Null     |
|  3 |      2 |        3 | David      | Jones        | Null         | Null           | Null     |          |
+----+--------+----------+------------+--------------+--------------+----------------+----------+----------+

所以在 Questions 表中 AnswerField Answer01 映射到 Answers 表中的 Answer01 列

我想做的是得到一个看起来像这样的结果集:

对于表单 ID 1 和记录 ID 1:

+--------------+---------------+
| QuestionText |    Answer     |
+--------------+---------------+
| Name         | Bob Smith     |
| Address      | Bobs Address  |
| Phone        | 01234 111222  |
| Email        | bob@smith.com |
+--------------+---------------+

那么对于表单 id 2 和记录 id 3:

+--------------+---------+
| QuestionText | Answer  |
+--------------+---------+
| First Name   | David   |
| Surname      | Jones   |
+--------------+---------+

我尝试过使用数据透视表:

SELECT QuestionText, Answer01, Answer02, Answer03, Answer04
FROM (
    SELECT DISTINCT Q.AnswerField, Q.QuestionText, Q.ID, A.Answer01, A.Answer02, A.Answer03, A.Answer04
    FROM Questions Q
    INNER JOIN Answers A ON A.FormId= Q.FormId
    WHERE A.ID = 17
) 
AS src
PIVOT (MAX(question_id) FOR Answer IN(answer_01, answer_02, answer_03, answer_04)) AS pvt

但这重复了所有列中的答案:

+--------------+-----------+--------------+--------------+---------------+
| QuestionText | Answer01  |   Answer02   |   Answer03   |   Answer04    |
+--------------+-----------+--------------+--------------+---------------+
| Name         | Bob smith | Bobs Address | 01234 111222 | bob@smith.com |
| Address      | Bob smith | Bobs Address | 01234 111222 | bob@smith.com |
| Phone        | Bob smith | Bobs Address | 01234 111222 | bob@smith.com |
| Email        | Bob smith | Bobs Address | 01234 111222 | bob@smith.com |
+--------------+-----------+--------------+--------------+---------------+

这显然是不对的。

谁能建议如何在 SQL Server 存储过程中完成此操作?

【问题讨论】:

【参考方案1】:

首先,您的Answers 表设计得非常糟糕。该表未规范化,这会在您想要返回数据时给您带来问题。如果可能,您需要重组该表。

如果您无法重新设计表格,那么您将不得不对答案表格进行反透视,以便能够轻松地连接问题的答案。

UNPIVOT 将获取您的列并将它们转换为行。 unpivot 代码将是:

select formid, RecordId, answer, answercol
from answers a
unpivot
(
  answer
  for answerCol in ([Answer01], [Answer02], [Answer03], 
                    [Answer04], [Answer05], [Answer06])
) unpiv;

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

| FORMID | RECORDID |         ANSWER | ANSWERCOL |
--------------------------------------------------
|      1 |        1 |      Bob Smith |  Answer01 |
|      1 |        1 |   Bobs Address |  Answer02 |
|      1 |        1 |   01234 111222 |  Answer03 |
|      1 |        1 |  bob@smith.com |  Answer04 |

数据成行后,您可以加入问题表以返回您想要的结果:

select q.questiontext, d.answer
from questions q
inner join
(
  select formid, RecordId, answer, answercol
  from answers a
  unpivot
  (
    answer
    for answerCol in ([Answer01], [Answer02], [Answer03], 
                      [Answer04], [Answer05], [Answer06])
  ) unpiv
) d
  on q.AnswerField = d.answercol
  and q.formid = d.formid
where d.recordid = 1;

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

| QUESTIONTEXT |        ANSWER |
--------------------------------
|         Name |     Bob Smith |
|      Address |  Bobs Address |
|        Phone |  01234 111222 |
|        Email | bob@smith.com |

【讨论】:

这似乎成功了!非常感谢。关于您对 Answers 表的评论,您能否就改进的结构提出建议?再次感谢。 @ChrisO 这是一个粗略的模型,但请参阅这个带有一些示例表的演示 -- sqlfiddle.com/#!3/dce4b 你知道SQLServer的UNPIVOT版本兼容性吗? @Fractaliste 数据库的兼容级别必须设置为 90 - 请参阅 msdn 文档 -- technet.microsoft.com/en-us/library/ms177410(v=sql.90).aspx

以上是关于如何在动态查询中将行值连接到列名的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 使用动态行值作为列名

通过特定行值动态获取列名

动态生成列名时如何获取kendo选择的行值

在 hive 中将多列连接为一列

如何在 django 的插入查询中动态使用列名

mysql选择动态行值作为列名,另一列作为值