Thursday, July 21, 2016

Left join returns too many rows. Need to combine certain columns

Saw this in a forum post on the MySQL web site...

Here's an example of the set up I'm using:
TITLES
id
name

DIRECTORS
id
name

ACTORS
id
name

MOVIES
id
movie_id
director_id

There can be several actors to a movie, so I use another join table:

MOVIES_ACTORS
id
movie_id
actor_id

This all works fine, except for one problem... i get several rows for one movie. So it comes out like this:

Star Wars - George Lucas - Harrison Ford
Star Wars - George Lucas - James Earl Jones
Star Wars - George Lucas - Yoda

King Kong - Peter Jackson - Jack Black

School of Rock - NULL - Jack Black

This is a problem because I don't want 3 results for Star Wars, I want one result row with 3 columns for the actors. Have three separate rows causes problems because:
1. If I were to limit the results to say, 3 I would only get Star Wars as a result.

2. When I display the results with PHP I have to build an elaborate array and loop through the result set 3 times just to avoid showing more than one result for the same movie in the list.

Here's my query:

SELECT
m.id, t.name, dir.name, act.name
FROM movies m
JOIN titles t ON t.id = m.title_id
LEFT OUTER JOIN directors dir ON dir.id = m.director_id
LEFT OUTER JOIN movies_actors ma ON ma.movie_id = m.id
LEFT OUTER JOIN actors a ON ma.actor_id = a.id



---------------------------------------------------------------
The solution is a GROUP_CONCAT on the terms you want to combine


SELECT m.id, t.name,
group_concat(dir.name) AS directors, group_concat(act.name) AS actors
FROM movies             AS m 
JOIN titles             AS t   ON t.id = m.title_id 
LEFT JOIN directors     AS dir ON dir.id = m.director_id 
LEFT JOIN movies_actors AS ma  ON ma.movie_id = m.id 
LEFT JOIN actors        AS a   ON ma.actor_id = a.id
GROUP BY t.name

It combines those columns as a comma-separated list.  You can also define a
separator...

GROUP_CONCAT(dir.name SEPARATOR '; ')
 

Monday, July 18, 2016

ESC characters in git diff output

You could change the pager to more, or just use the following to process the raw characters in less...

git config --global core.pager "less -r"