具有许多表的复杂查询,这在一个查询中是否可行?

时间:2012-06-12 10:35:34

标签: mysql sql

我遇到以下数据库设计的麻烦(示例简化)。它允许人们创建自定义表单,与google spreadsheat表单非常相似。表单生成脚本已完成,包括保存数据库的答案。我无法显示用户输入。

表单(每个表单是此表中的一行)

form_id | form_name
1         Contact Form
2         BBQ sign up Form

问题(表单中的问题)

question_id | form_id | question_name      | sorting_order
1             1         Full Name            1
2             1         E-mail address       2
3             1         Subject              3
4             1         Message              4
5             2         Your name            1
6             2         Are you vegetarian?  2
7             2         Beer or wine?        3    

completed_forms (将答案分组)

complete_id | form_id | timestamp
1            1          1339496914
2            1          1148691493
3            2          1256235334

答案(用户对特定问题的回答)

answer_id | complete_id | question_id | answer
1           1             1             Barack Obama
2           1             2             president@whitehouse.gov
3           1             3             Test message
4           1             4             This is a test. Regards, Barack.
5           2             1             Thomas something
6           2             2             thomas@email.com
7           2             3             Another message
8           2             4             Hey, it's Thomas. This is my message.
9           3             5             Dirk
10          3             6             No, I love meat
11          3             7             Red wine!

我想要显示的是用户输入的概述,由于每个表单的名称和列数不同而非常复杂。例如,我想从联系表单(form_id:1)显示用户输入,如下所示:

id | timestamp | Full Name | E-mail Address | Subject | Message
1    133949...   Barack...   president@w...   Test...   This is a t...
2    114869...   Thomas...   thomas@emai...   Anot...   Hey, it's T...

从form_id 2开始如下:

id | timestamp | Your name | Are you vegetarian? | Beer or Wine?
3    125623...   Dirk        No, I love meat       Red wine!

有没有人能否以及如何实现这一目标?

非常感谢任何愿意花时间来解决这个问题的人!

2 个答案:

答案 0 :(得分:3)

基本上你正在尝试编写一个PIVOT,但MySQL本身没有PIVOT函数,所以你必须编写一个稍微不同的查询。对于此查询的静态版本,您将使用以下代码编写问题的值:

表格1(见SQL Fiddle with Demo):

select cf.complete_id
  , cf.ts
  , Min(CASE WHEN q.question_name = 'Full Name' THEN a.answer END) as 'Full Name'
  , Min(CASE WHEN q.question_name = 'Email Address' THEN a.answer END) as 'Email Address'
  , Min(CASE WHEN q.question_name = 'Subject' THEN a.answer END) as 'Subject'
  , Min(CASE WHEN q.question_name = 'Message' THEN a.answer END) as 'Message'
from completed_forms cf
inner join questions q
  on cf.form_id = q.form_id
inner join answers a
  on cf.complete_id = a.complete_id
  and q.question_id = a.question_id
where cf.form_id = 1
group by cf.complete_id

表格2(见SQL Fiddle with Demo):

select cf.complete_id
  , cf.ts
  , Min(CASE WHEN q.question_name = 'Your Name' THEN a.answer END) as 'Your Name'
  , Min(CASE WHEN q.question_name = 'Are you vegetarian?' THEN a.answer END) as 'Are you vegetarian?'
  , Min(CASE WHEN q.question_name = 'Beer or Wine' THEN a.answer END) as 'Beer or Wine'
from completed_forms cf
inner join questions q
  on cf.form_id = q.form_id
inner join answers a
  on cf.complete_id = a.complete_id
  and q.question_id = a.question_id
where cf.form_id = 2
group by cf.complete_id

现在,由于您的问题将针对每个表单进行更改,因此您应该考虑自动化Pivot。我建议查看这里的文章:

http://www.artfulsoftware.com/infotree/queries.php#523

它包含如何在MySql中使用数据透视的示例。 StackOverflow上还有其他答案应该能够帮助动态编写它:

mysql query to dynamically convert row data to columns

MySQL pivot table with dynamic headers based on single column data

答案 1 :(得分:1)

很好的规范化架构!

在纯SQL中执行此操作非常困难,因为您需要创建具有列名别名的查询,这些别名来自questions.question_name中的行。

如果您是在纯SQL中执行此操作,那么您将编写SQL语句,以某种方式为form_id的每个不同值编写SQL语句。这会导致SQL代码中出现一些无法维护的猴子业务。它会彻底扼杀你所做的工作,以便在长期成本方面轻松处理多种形式。

这在PHP,PERL,Java或其他一些操作字符串列表方面做得不错的语言要容易得多。

PostgreSQL和Oracle允许您使用Java和/或PERL等语言编写存储过程。如果您必须将此代码驻留在您的DBMS中,那么这可能是要走的路。