首页 > 解决方案 > 如何使用 MySQL 分别对列进行计数和分组?

问题描述

我有一个调查应用程序,我正在处理结果页面。对于每个问题,页面应显示提供的不同答案以及每个问题提供了多少次。

有些问题可以接受多个答案。例如,假设以下是这样一个问题:

  1. 你感觉怎么样?

这意味着Good,Bad和/或的任何组合Okay都可以作为答案。

假设调查的回答如下:

以下是预期的结果:

  1. 你感觉怎么样?

我的代码提供

  1. 你感觉怎么样?

此示例的数据库条目如下所示:

问号 问题 答案1 答案2 答案3 ...
1 你感觉怎么样? 好的 坏的 好的
1 你感觉怎么样? 好的 坏的 好的
1 你感觉怎么样? 好的 坏的
1 你感觉怎么样? 好的 坏的
1 你感觉怎么样? 好的
1 你感觉怎么样? 好的
1 你感觉怎么样? 好的

这是我的代码:

my $queryQuery = "SELECT questionNum, question, answer1, answer2, answer3, answer4, answer5, answer6, answer7, answer8, answer9, answer10, COUNT(*) FROM results WHERE title = ? GROUP BY answer1, answer2, answer3, answer4, answer5, answer6, answer7, answer8, answer9, answer10 ORDER BY questionNum";
my $sthm = $dbh->prepare($queryQuery);
$sthm->execute($marathon);

my $prev_question;
while(my($questNumber, $quest, $ans1, $ans2, $ans3, $ans4, $ans5, $ans6, $ans7, $ans8, $ans9, $ans10, $count) = $sthm->fetchrow_array){
print qq{<tr><td> $questNumber. $quest \n </td></tr>} unless $quest eq $prev_question; # the trailing conditional is to get rid of the duplicate questions that print out.
print qq{<tr><td> $ans1 = $count </td></tr>} unless $ans1 eq "";
print qq{<tr><td> $ans2 = $count </td></tr>} unless $ans2 eq "";
print qq{<tr><td> $ans3 = $count </td></tr>} unless $ans3 eq "";
print qq{<tr><td> $ans4 = $count </td></tr>} unless $ans4 eq "";
print qq{<tr><td> $ans5 = $count </td></tr>} unless $ans5 eq "";
print qq{<tr><td> $ans6 = $count </td></tr>} unless $ans6 eq "";
print qq{<tr><td> $ans7 = $count </td></tr>} unless $ans7 eq "";
print qq{<tr><td> $ans8 = $count </td></tr>} unless $ans8 eq "";
print qq{<tr><td> $ans9 = $count </td></tr>} unless $ans9 eq "";
print qq{<tr><td> $ans10 = $count </td></tr>} unless $ans10 eq "";
$prev_question = $quest;
}

在这里,我循环查询以打印出所有没有重复的问题,并打印带有问题的答案,只要它们不为空。这是我正在搜索上述输出的地方 1。你感觉如何?好 = 7,坏 = 4,好的 = 2。
相反,我将答案分成几组,因为用户使用复选框而不是单选按钮为单个问题选择了多个答案。因此,在数据库内部,即使答案已被放入它们自己的列中,它们也是相互连接的,因为它们是由用户选择问题选项同时输入的。

标签: mysqlgroup-by

解决方案


我知道您同时在很多事情上苦苦挣扎,但最好的答案解决了ikegami在使用 Perl 的过程中迅速忽略的问题:

这是一个可怕的数据库模式。

人们通常在应用程序级别做的事情比他们需要做的多得多,因为他们从来没有学会在数据库中做正确的事情(比如你的其他问题,最好通过适当的 SQL 查询而不是 Perl 来回答)。但是,顺便说一句,许多人这样做是因为他们无法更改架构。社会启发法,例如啤酒的适当应用,有时会平滑这条道路。说服数据库人员的一点工作以后会成倍地得到回报。而且,另外,“全栈开发人员”经常忽略对数据库的任何复杂使用。

我不会让任何人深入阅读 CJ Date 的数据库,但正确获取架构有很多价值。正确地说,我的意思是它在使用上付出了最少的努力和复杂性。事情应该很容易,您不必在应用程序级别重新安排这些事情。

您想计算每个答案被选中的次数。计数是数据库做得很好的事情,所以让数据库来做吧。

你有一些问题。问题有不同的答案。调查将一组问题组合在一起。人们通过将他们的答案与问题相关联来回应调查。

这是一个简单的模式设计(一些数据库人员最终会出现并告诉我我没有做对,但这很好)。诀窍是没有任何东西必须有多个未使用的列。一切都放在一个简洁的小包中(“关系数据库”中的“关系”),可以通过“外键”轻松连接到其他东西(例如,question_id 映射问题的答案)。例如,答案将有多个相同的question_id.

如果有人想使用精美的建模工具制作图片,那就去吧。我将其标记为社区 wiki。

Table: Questions
   id
   text

Table: Answers
   id
   text
   question_id

Table: Surveys
   id 
   title

Table: SurveyQuestionSet
   id
   survey_id
   question_id   

Table: Respondent
   id
   text

Table: Response
   id
   respondent_id
   survey_id
   question_id
   answer_id

一旦映射出来并正确规范化(阅读正常形式),就很容易使用 SELECT 获得所需的数据。规范化的理想就是不重复信息或让它进入不一致的状态。在这些形式中,许多事情变得更容易做。

而且,如果你想练习这样的事情,Stackoverflow 数据资源管理器是一个真实的数据集,标准化为我在这里展示的内容。

现在,您只需计算answer_id调查和问题的特定组合出现的次数。巧妙地使用GROUP BY为您完成所有工作。您不再需要遍历行来查看数十个未使用的列来试图弄清楚如何计算它们。不仅如此,您还可以使这些东西成为视图,这意味着您只需编写一次查询,数据库就会将其结果伪装成一个表。然后,您可以简单地查询视图(因此所有JOINs 和同样被隐藏),这非常简单。存储过程也经常被忽视。


推荐阅读