我遇到以下数据库设计的麻烦(示例简化)。它允许人们创建自定义表单,与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!
有没有人能否以及如何实现这一目标?
非常感谢任何愿意花时间来解决这个问题的人!
答案 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中,那么这可能是要走的路。