【问题标题】:mysql join repeats row, order by caused problemmysql join重复行,顺序由引起的问题
【发布时间】:2019-02-08 09:47:03
【问题描述】:

我正在尝试获取每个班级名称、该班级的学生以及分配给该班级的科目。

这里,问题是由ORDER BY 引起的,我已将ORDER BY 分配给student.id

这会导致主题行重复

如果未分配ORDER BY,则按预期提取主题行,不重复,但学生行重复

表结构

学生

id  |   Rid |   class   |   name
================================
1   |   1   |   1       |   John
2   |   2   |   1       |   Harsita

id  |   title
==============
1   |   One
2   |   two
3   |   three

主题

id  |   title
===============
1   |   science
2   |   math
3   |   english
4   |   social
5   |   hpe

class_subject

id  |   class   |   subject
===========================
1   |   1       |   1   
2   |   1       |   2
3   |   1       |   3
4   |   1       |   4

要求是

class: One
Science | Math | English | Social | Hpe | 
John | Harsita 

但我得到了什么

如果ORDER BY 分配给student.id

class: One
Science | Math | English | Social | Hpe | Math | English | Social | Hpe | Science | 
John | Harsita |

如果ORDER BY没有分配给student.id

class: One
Science | Math | English | Social | Hpe | 
John | Harsita | John | Harsita | John | Harsita | John | Harsita | John | Harsita | 

我尝试使用GROUP BYsubject.id,它只显示一个学生(第一行:John)。问题出在哪里?不使用subqueryGROUP_CONCAT如何解决

代码 - php 和 mysql(带有 ORDER BY)

//mysql query
    SELECT 
        DISTINCT class_subject.class, 
        subject.title AS sub,
        student.name AS stdt,
        class.title AS class
    FROM 
        student
    INNER JOIN class_subject ON class_subject.class=student.class
    INNER JOIN subject ON subject.id=class_subject.subject
    INNER JOIN class ON class.id=student.class
    WHERE
        student.class=:cid;

//php
    $class='';
    $stdt='';
    $sub='';
    $results = Array();
        while($row=$result->fetch(PDO::FETCH_ASSOC)){
            if ($row['class'] != $class){
                $class = $row['class'];
                echo "Class: ".$class."<br/>";
            }
            if ($row['sub'] != $sub){
                $sub = $row['sub'];
                echo $sub." | ";
            }
            $results[]=$row;
        }
        echo "<br/>";
        foreach ($results as $row) {
            if ($row['stdt'] != $stdt) {
                $stdt = $row['stdt'];
                echo $stdt." | ";
            }
        }

【问题讨论】:

    标签: php mysql


    【解决方案1】:

    您的问题是由所有JOINs 引起的。 1班有4个科目,2个学生。因此,您将在结果中得到 4*2 = 8 行。如您所见,连接的结果将是 4 个学科名称中的 2 组,或者 2 个学生姓名中的 4 组。你可以选择在你的 PHP 代码中处理这个问题,或者因为你在 PHP 代码中有效地分组,所以在你的查询中进行分组:

    SELECT 
        c.title AS class,
        GROUP_CONCAT(DISTINCT s.title ORDER BY s.title SEPARATOR ' | ') AS subjects,
        GROUP_CONCAT(DISTINCT t.name ORDER BY t.name SEPARATOR ' | ') AS students
    FROM class c
    JOIN class_subject cs ON cs.class=c.id
    JOIN subject s ON s.id=cs.subject
    JOIN student t ON c.id=t.class
    WHERE c.id=1
    GROUP BY class
    

    输出:

    class   subjects                            students
    One     english | math | science | social   Harsita | John
    

    请注意,您可以在GROUP_CONCAT 中指定ORDER BY 来控制组中值的顺序。

    【讨论】:

    • 感谢您的回答,我想知道,是否可以不使用GROUP_CONCAT。所以我在问题中使用了 without GROUP_CONCAT 这个词。
    • 抱歉,我错过了问题的那一部分。没有GROUP_CONCAT,您的问题中的示例数据最终将得到 8 行数据,您必须在 PHP 代码中处理这些数据。当您向每个班级添加更多科目和学生时,情况会变得更糟。唯一的另一种选择是 2 个查询,一个选择与一个班级关联的所有科目,另一个选择与一个班级关联的所有学生。
    • 这就是重点,我认为性能 2 查询会比 GROUP_CONCAT 更好,不是吗?因为GROUP_CONCAT() 调用 group-by 逻辑并创建临时表,这可能对性能造成很大的负面影响,不是吗?
    • 我认为GROUP_CONCAT 不一定会对性能产生如此大的影响。但这可能是您需要在自己的环境中对其进行基准测试的事情之一。但是,考虑到您通过 2 个简单查询来实现您想要的目标是多么容易,这可能会更快。
    【解决方案2】:

    查看您的预期结果样本,您似乎需要名称和主题的汇总结果

    SELECT 
        group_concat( subject.title) AS sub,
        group_concat(student.name) AS stdt,
        class.title AS class
    FROM 
        student
    INNER JOIN class_subject ON class_subject.class=student.class
    INNER JOIN subject ON subject.id=class_subject.subject
    INNER JOIN class ON class.id=student.class
    WHERE student.class=:cid
    group by class.title
    

    使用聚合函数和分组可以在同一行显示聚合结果

    【讨论】:

    • 感谢您的回答,是否可以在不使用GROUP_CONCAT 的情况下获取预期结果?我想避免GROUP_CONCAT。所以我在问题中使用了 without GROUP_CONCAT 这个词。
    • 如果您希望查询结果在同一行上,您必须使用聚合函数作为 group_concat 和 group by ... 否则您可以执行您在问题中使用的相同查询并使用格式化结果php .. 构建输出所需的字符串 ..
    • 无论如何......为什么你不想要 group by 和 group concat ? .. 你选择几行过滤器的事实是:cid .. 并且你有正确的 joi 索引列你不能有性能问题..
    • GROUP_CONCAT() 调用 group-by 逻辑并创建临时表,这可能会对性能产生很大的负面影响。阅读这篇文章后 - [stackoverflow.com/questions/26225069/…,如果可能的话,我会尽量避免。
    • 那么您的性能要求是什么..? ..每个表涉及多少行? ..每个cid平均涉及多少行..?如果您涉及数十亿行,并且对于这数十亿行,您需要响应一些小数秒,那么您的表现您的担忧是有道理的.. 否则.. 不是.. .. 您应该尝试在 sql 控制台中执行查询或sql IDE并检查您的真实计时结果...您应该阅读有问题但与实际问题相关的答案..而不是简单地转置答案t
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    • 2011-01-06
    • 2017-03-26
    • 2021-10-02
    • 2011-09-15
    相关资源
    最近更新 更多