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