【问题标题】:How can I count and group columns separately with MySQL?如何使用 MySQL 分别对列进行计数和分组?
【发布时间】:2021-03-23 22:39:39
【问题描述】:

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

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

  1. 感觉怎么样?
  • 不好
  • 好的

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

假设调查结果如下:

  • 调查 1:GoodBadOkay
  • 调查 2:GoodBadOkay
  • 调查 3:GoodBad
  • 调查 4:GoodBad
  • 调查 5:Good
  • 调查 6:Good
  • 调查 7:Good

以下是预期的结果:

  1. 感觉怎么样?
  • 好 = 7
  • 坏 = 4
  • 好的 = 2

我的代码交付

  1. 感觉怎么样?
  • 好 = 3
  • 坏 = 2
  • 好 = 4
  • 好的 = 1
  • 坏 = 2
  • 好的 = 1

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

questionNum question answer1 answer2 answer3 ...
1 How are you feeling? Good Bad Okay
1 How are you feeling? Good Bad Okay
1 How are you feeling? Good Bad
1 How are you feeling? Good Bad
1 How are you feeling? Good
1 How are you feeling? Good
1 How are you feeling? Good

这是我的代码:

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。
相反,我将答案分为几组,因为用户使用复选框而不是单选按钮为单个问题选择了多个答案。因此,在数据库内部,即使答案已被放入它们自己的列中,它们也是相互连接的,因为它们是由用户选择问题选项同时输入的。

【问题讨论】:

  • 首先修复您的架构。数据库表不是电子表格。
  • Edit 问题并提供minimal reproducible example,即表格的CREATE 语句(粘贴文本,不要使用图像),@987654342 @ 用于示例数据 (dito) 的语句以及带有表格文本格式的示例数据的所需结果。
  • 正如我之前提到的,清楚地描述您的数据。我仍然不知道它是什么,你甚至没有试图描述它
  • @ikegami 我没有证明打印在我身上的代码的格式。这更好吗?我很乐意澄清其他任何事情。
  • @Strawberry 我应该在提交之前仔细查看,我的错误。这个样子怎么样?我很乐意澄清其他任何事情。

标签: mysql group-by


【解决方案1】:

我知道你同时在很多事情上苦苦挣扎,但最好的答案解决了ikegami quickly passed 在 Perl 中解决的问题:

这是一个可怕的数据库架构。

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

我不会让任何人阅读 C.J. Date 的 Database in Depth,但正确设置架构有很多价值。正确地说,我的意思是它在使用上付出了最少的努力和复杂性。事情应该很简单,您不必在应用程序级别重新安排这些事情。

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

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

这是一个简单的架构设计(一些数据库人员最终会出现并告诉我我没有做对,但这很好)。诀窍是没有任何东西必须有多个未使用的列。一切都放在一个简洁的小包中(“关系数据库”中的“关系”),可以通过“外键”轻松连接到其他东西(例如,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

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

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

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

【讨论】:

  • 感谢您的详细回答。我对编程很陌生,对 Perl 也很陌生。我感谢所有包含的链接。如您所知,我的数据库经验很少。我有很多阅读要做,其中大部分来自不知道我不知道的东西。我会留下来,我不介意阅读文档,因为它会让我成为一个更好的程序员。我将继续修改此代码,直到我做对为止。附言。我希望你收到这个通知。我试图“@”你,但你的用户名中有空格,我不知道这是否是正确的做法。
【解决方案2】:

您需要将(糟糕的)数据模型转换为更有用的东西。这是您需要执行的那种摆弄才能获得您正在寻找的结果。

select questionNum ,question ,answer, count(*) as num_of
from (
  select questionNum ,question ,answer1 as answer FROM results where answer1 IS NOT NULL union all
  select questionNum ,question ,answer2 as answer FROM results where answer2 IS NOT NULL  union all
  select questionNum ,question ,answer3 as answer FROM results where answer3 IS NOT NULL  union all
  select questionNum ,question ,answer4 as answer FROM results where answer4 IS NOT NULL  union all
  select questionNum ,question ,answer5 as answer FROM results where answer5 IS NOT NULL  union all
  select questionNum ,question ,answer6 as answer FROM results where answer6 IS NOT NULL  union all
  select questionNum ,question ,answer7 as answer FROM results where answer7 IS NOT NULL  union all
  select questionNum ,question ,answer8 as answer FROM results where answer8 IS NOT NULL  union all
  select questionNum ,question ,answer9 as answer FROM results where answer9 IS NOT NULL  union all
  select questionNum ,question ,answer10 as answer FROM results where answer10 IS NOT NULL
  ) as fiddle
group by  questionNum ,question ,answer

为了避免以后出现这种情况,您真的应该考虑重新安排桌子。随之而来的往往是随着时间的推移,小提琴变得越来越难以创建。所以请花一些时间重新考虑您的数据模型。

【讨论】:

  • 谢谢。我正在提高我的数据库技能。
【解决方案3】:

这是一个可怕的数据库架构。

这在 Perl 中会容易得多。

my %counts_by_answer_by_qid;
{
   my $sql = '
      SELECT `questionNum`,
             `answer1`, `answer2`, `answer3`, `answer4`, `answer5`,
             `answer6`, `answer7`, `answer8`, `answer9`, `answer10`
        FROM `results`
       WHERE `title` = ?
   ';

   my $sth = $dbh->prepare($sql);
   $sth->execute($title);

   while ( my ($questionNum, @answers) = $sth->fetchrow_array ) {
      ++$counts_by_answer_by_qid{$questionNum}{$_} for grep length, @answers;
   }
}

{
   my $sql = '
      SELECT DISTINCT
             `questionNum`,
             `question`
        FROM `results`
       WHERE `title` = ?
       ORDER BY `questionNum`
   ';

   my $sth = $dbh->prepare($sql);
   $sth->execute($title); 

   while ( my ($questionNum, $question) = $sth->fetchrow_array ) {
      my $counts_by_answer = $counts_by_answer_by_qid{$questionNum} // {};
      say "$questionNum. $question";

      for my $answer (
         sort { $counts_by_answer->{$b} <=> $counts_by_answer->{$a} }
            keys(%$counts_by_answer)
      ) {
         my $count = $counts_by_answer->{$answer};
         say "* $answer = $count";
      }
   }
}

【讨论】:

  • 谢谢你。我现在正在阅读您的代码以确保我理解它。我假设尽管 sql 查询都具有相同的名称 $sql 它们是具有差异语句句柄的差异查询?还是您只是在每次使用后再次声明它们?
  • 只存在于声明它们的花括号中的新变量
  • 也是第一个括号“{”和最后一个括号“}”。这些是用于stackoverflow还是这也是代码?抱歉,我是新来的,对 Perl 还很陌生。我看到所有循环都打开和关闭,这些似乎是额外的。在最后一个 while 循环中,您要声明 $counts_by_answer 的第二行。我将 $question_id 视为一个新变量。这应该在那里吗?我没有看到之前用“my”声明它的位置。
  • 好的。再次感谢!
  • 修复了缺失的准备+执行。修复了 $question_id$questionNum。这些卷曲了每个 $sql$sth 的范围
猜你喜欢
  • 2010-12-08
  • 2015-09-24
  • 2013-05-20
  • 1970-01-01
  • 2021-01-31
  • 2012-03-29
  • 1970-01-01
  • 2017-03-05
  • 1970-01-01
相关资源
最近更新 更多