group_concat()
Bài đăng này đã không được cập nhật trong 10 năm
Background
One of the common problem with RDBMS is that it can not handle well has-many relation by a single query. As ActiveRecord's eage load does, we need two separate queries to load parent and child tables. I believed this as a matter of fact until I know about group_concat().
Solution
group_concat() is a MySQL's embedded function that allows us to load associated has-many data as a single column with GROUP BY clause. Let's look at an example.
Think about the following two tables.
CREATE TABLE projects (
id int not null auto_increment,
name varchar(255),
primary key(id)
);
CREATE TABLE members (
id int not null auto_increment,
name varchar(255),
is_leader boolean,
project_id int not null,
primary key(id)
);
Obviously a project has many members. We want to implement a page which shows a table containing
- project name
- each member's name separated by comma, and leaders's name comes first.
If you implement this naively, it would look like this:
@projects = Project.preload(:members).to_a
view
- @projects.each do |project|
  tr
    td= project.name
    td= project.members.sort_by(&:is_leader).map(&:name).join(",")
It will show something like this
| Project | Members | 
|---|---|
| Sakura | Alice,Bob,Caroll | 
| Ume | Dean,Edison,Fox | 
But sometimes we want to avoid loading has-many association and building many models, because as we know building ActiveRecord instances are one of the most costly operation in RoR.
We can solve this problem bygroup_concat().
SELECT p.name,
       group_concat(m.name ORDER BY m.is_leader DESC) AS members
  FROM projects p
       INNER JOIN members m
          ON m.project_id = p.id
 GROUP BY p.id
Then it will show a result like this.
+--------+------------------+
| name   | members          |
+--------+------------------+
| Sakura | Alice,Bob,Caroll |
| Ume    | Dean,Edison,Fox  |
+--------+------------------+
So we can load desired data by a single query.
Notice that we can use ORDER BY in group_concat().
Conclusion
group_concat is sometimes useful for optimizing a query for has_many relation.
All rights reserved
 
  
 