group_concat()
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 ...
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.