2014-03-06 87 views
1

我遇到了获取数据的问题。我想找到所有的课程,其中包含where子句中的标志,并获取它包含的所有标志。GROUP_CONCAT和INNER JOIN与WHERE子句

记录为当然表:

+----+----------+ 
| id | name | 
+----+----------+ 
| 1 | Spring | 
| 2 | Hibernate| 
| 3 | C#  | 
+----+----------+ 

记录为course_flags表:

+----+----------+----------+ 
| id |course_id | flag_id | 
+----+----------+----------+ 
| 1 |  1 |  1 | 
| 2 |  1 |  2 | 
| 3 |  2 |  1 | 
+----+----------+----------+ 

记录为标志表:

+----+------------+ 
| id | name | 
+----+------------+ 
| 1 | promocja | 
| 2 |last minute | 
+----+------------+ 

我查询

SELECT course.id, course.name, 
     GROUP_CONCAT(Flag.id SEPARATOR ',') as flags 
FROM course 
INNER JOIN course_flags ON 
    course.id = course_flags.course_id 
INNER JOIN flag ON 
    flag.id = course_flags.flag_id 
WHERE flag.name LIKE 'promocja' 
GROUP BY Course.id 

不幸的是我的数据库引擎返回的记录与一个标志标志柱:

+----+----------+----------+ 
| id | name | flags | 
+----+----------+----------+ 
| 1 | Spring |  1 | 
| 2 | Hibernate|  1 | 
+----+----------+----------+ 

我原本希望得到这样的结果:

+----+----------+----------+ 
| id | name | flags | 
+----+----------+----------+ 
| 1 | Spring | 1,2 | 
| 2 | Hibernate| 1  | 
+----+----------+----------+ 

问题我如何得到它?

在此先感谢!

+1

注意:您的GROUP BY子句更正确的是GROUP BY course.id,course.name。正如你所写,你的查询在大多数RDBMS上不起作用,因为它是不明确的。 MySQL只是选择忽略这个事实和猜测以及你的意思。只要'course.id'是一个主键,你就会好起来的,但是最好指定一个你想要的字段。 –

回答

2

WHERE子句将记录之前的限制为分组;而HAVING子句限制后分组结果

SELECT course.id, course.name, GROUP_CONCAT(Flag.id) flags 
FROM  course 
    JOIN course_flags ON course_flags.course_id = course.id 
    JOIN flag ON flag.id = course_flags.flag_id 
GROUP BY Course.id 
HAVING SUM(flag.name = 'promocja') 

见它sqlfiddle

+0

它的工作原理!非常感谢你! – Piotr

+0

虽然这是一个有效的解决方案,但取决于标志数据的基数,使用子选择预先过滤课程标识可能更有意义。 OP应该测试两种方式,以查看哪些更适合他的用例。 –

+0

@MikeBrant:同意。我更多地通过展示“WHILE”与“HAVING”的问题效果而不是解决任何特定(未提及的)性能问题的方式发布此答案。 – eggyal

2

与单纯使用问题加入类似的是,你的WHERE子句将减少可用的结果集的标志。你真正需要做的就是使用一个子查询来首先确定拥有这个标记的id,然后使用这组id来确定每个id的标记。可能是这样的:

SELECT 
    c.id AS id, 
    c.name AS name, 
    GROUP_CONCAT(cf.flag_id) AS flags 
FROM course AS c 
INNER JOIN course_flag AS cf 
    ON c.id = cf.course_id 
INNER JOIN 
    (SELECT cf2.course_id AS id 
    FROM course_flags AS cf2 
    INNER JOIN flag AS f 
    WHERE f.name = ?) AS ids 
    ON c.id = ids.id 
GROUP BY c.id 

哪里?是您要查询的标志名称。注意我还使用=这里WHERE条款而不是LIKE因为你甚至没有使用LIKE功能(你没有通配符)。