group by和group_concat替代

时间:2018-09-01 01:52:27

标签: php mysql

使用GROUP_CONCAT()通常会调用分组逻辑并创建临时表,这通常会对性能产生很大的负面影响。有时,您可以添加正确的索引来避免按组查询中的临时表,但并非在每种情况下都如此。

https://stackoverflow.com/a/26225148/9685125

阅读这篇文章后,我意识到自己做错了,因为很多时候我都使用巨大的GROUP_CONCAT()进行复杂的查询。如

GROUP_CONCAT(DISTINCT exam.title) AS exam,
GROUP_CONCAT(subject.title, '<br/> Th - ', mark.th, ' | PR - ', mark.pr SEPARATOR ',') AS mark

但是在以下情况下,不用GROUP_CONCAT可以替代subquery。我的意思是只使用Mysql join

例如,让我们看两个关系数据库,然后查询以解释我的问题

学生

id  |   Rid |   name
========================
1   |   1   |   john

标记

id  |   std_id  |   th
======================
1   |   1       |   60
2   |   1       |   70
3   |   1       |   80
4   |   1       |   90

"SELECT 
    student.en_name, mark.th 
    FROM student
    JOIN mark ON student.id = mark.std_id
    WHERE student.id=:id;"

如果仅使用JOIN

,则会重复该列
John: 60, John: 70, John: 80, John: 90

因此,我使用GROUP BY。但是,如果我将GROUP BY分配给student.id,则只会获取第一行

"SELECT 
    student.en_name, mark.th 
    FROM student
    JOIN mark ON student.id = mark.std_id
    WHERE student.id=:id
    GROUP BY student.id;"

Result is
John: 60

要获得结果,我们必须分配group.concat

"SELECT 
    student.en_name,
    GROUP_CONCAT(mark.th) as mark 
    FROM student
    JOIN mark ON student.id = mark.std_id
    WHERE student.id=:id
    GROUP BY student.id;"

使用爆炸数组的最终结果和预期结果

$name=$row['en_name'];
echo "$name: <br/>";
$mrk_array = explode(',',$row['mark']); 
foreach($mrk_array as $mark){
    echo $mark.", ";
}

John:
60, 70, 80, 90,

在这里,我看不到GROUP_CONCAT的任何替代方法来获取每个Id的所有关联值并防止重复,请从这里帮助我如何替换GROUP_CONCAT

还有,一个朋友告诉我

所以,如果要“爆炸”它,为什么要GROUP_CONCAT。您最好返回一个不错的关联数组,然后在此处显示它。

但是我不明白,他是什么意思?

1 个答案:

答案 0 :(得分:2)

评论太久了...

使用原始查询,您将有效地返回一个行数组(关联数组):

array(array('en_name' => 'John', 'mark' => 60),
      array('en_name' => 'John', 'mark' => 70),
      array('en_name' => 'John', 'mark' => 80),
      array('en_name' => 'John', 'mark' => 90)
     )

使用GROUP BYGROUP CONCAT时,实际上就是该数组的imploding元素'mark'

array('en_name => 'John', 'mark' => '60,70,80,90')

然后必须再次explode数组以处理数据。

如果您坚持使用原始查询,则可以在应用程序框架中进行内插,例如

$name = "";
while ($row = $result->fetch()) {
    if ($row['en_name'] != $name) {
        $name = $row['en_name'];
        echo "$name: <br/>" . $row['mark'];
    }
    else {
        echo ',' . $row['mark'];
    }
}

输出:

John: 
60,70,80,90

这通常比在数据库中使用GROUP BYGROUP_CONCAT要快得多。