我正在寻找一种(清洁?)方式来执行以下操作:
让我们说我有一个表,main,有~15列看起来像这样,每个id有一行:
main: id start end col4 ... col15 666 2014-01-01 2014-06-30 ... ... ... 1234 2015-03-05 2015-05-02 ... ... ... 9876 2014-09-01 2015-01-01 ... ... ... ...(etc)
然后我有另一个表,事件,每个id可能有0行,1行或多行:
events: id date code 666 2014-01-20 "code_a" 1234 2015-05-01 "code_b" 666 2014-01-25 "code_c" 666 2014-02-09 "code_z" ... (etc)
最后我有一个表,代码,每个代码有一行,给出代码的描述以及类型(0,1或2):
codes: code desc type "code_a" "something" 0 "code_b" "somethn else" 1 "code_c" "another thing" 0 "code_d" "one more" 2 (no code z)
和我想要的结果是主要的15列加上三个附加列,其中包含逗号分隔的事件代码列表,这些事件代码在类型的id的开始日期和结束日期之间发生(第一列是类型0,第二种类型1,第三种类型2),所以:
id start end ... col15 type_0 type_1 type_2 666 2014-01-01 2014-06-30 ... ... "code_a,code_c" 1234 2015-03-05 2015-05-02 ... ... "code_b" ...(etc)
我的解决方案是
select m.*
, group_concat(c0.code) as type_0
, group_concat(c1.code) as type_1
, group_concat(c2.code) as type_2
from main m
left join events e on m.id = e.id and e.date between m.start and m.end
left join codes c0 on c0.code = e.code and c0.type = 0
left join codes c1 on c1.code = e.code and c1.type = 1
left join codes c2 on c2.code = e.code and c2.type = 2
group by m.id
, m.start
, m.end
, m.col4
, m.col5
, m.col6
, m.col7
, m.col8
, m.col9
, m.col10
, m.col11
, m.col12
, m.col13
, m.col14
, m.col15
但对我来说这看起来很讨厌。有没有更优雅的方法来做到这一点(特别是避免组中列出的15列)?
答案 0 :(得分:1)
在MySQL中,您只需使用GROUP BY m.id
即可。除非您启用ONLY_FULL_GROUP_BY
选项,否则它允许您使用不在GROUP BY
子句中的非聚合列。如果您选择的列不是由分组列唯一标识的,那么这可能会产生前所未有的结果,但这不是这种情况 - 您按照m
表的唯一ID列进行分组,并且所有非聚合列来自同一个表。
在严格的SQL中,您必须通过在子查询中执行GROUP_CONCAT
来执行此操作,然后将其与main
表连接。
SELECT *
FROM (SELECT m.id,
, group_concat(c0.code) as type_0
, group_concat(c1.code) as type_1
, group_concat(c2.code) as type_2
FROM main m
left join events e on m.id = e.id and e.date between m.start and m.end
left join codes c0 on c0.code = e.code and c0.type = 0
left join codes c1 on c1.code = e.code and c1.type = 1
left join codes c2 on c2.code = e.code and c2.type = 2
GROUP BY m.id
) t1
JOIN main m ON t1.id = m.id
答案 1 :(得分:0)
另一个较短的版本如下所示,首先获取分组然后再加入它。
select m.*
, XX.type_0
, XX.type_1
, XX.type_2
from main m
left join events e on m.id = e.id and e.date between m.start and m.end
left join (
select code, GROUP_CONCAT(case when type = 0 then code else null end SEPARATOR ', ') AS type_0,
GROUP_CONCAT(case when type = 1 then code else null end SEPARATOR ', ') AS type_1,
GROUP_CONCAT(case when type = 2 then code else null end SEPARATOR ', ') AS type_2
from codes
group by <some_column> )XX ON XX.code = e.code;
答案 2 :(得分:0)
&#34;每个id一行&#34;在规范中,您可以利用GROUP BY
的MySQL扩展,它允许您在SELECT列表中包含非聚合。查询所需的唯一更改是
GROUP BY m.id
其他数据库会引发错误。如果我们在会话的ONLY_FULL_GROUP_BY
中包含sql_mode
,我们也可以让MySQL抛出错误。
另一种方法是使用内联视图避免对GROUP BY
进行m
操作。您仍然需要执行GROUP BY
,但是您可以在内联视图中执行此操作,其中main
中的其他列未返回,我们只返回唯一id
值。我们需要在外部查询中加入。
您似乎只需要一个加入codes
表;你可以在GROUP_CONCAT中使用条件测试来有条件地返回代码的值。
例如:
SELECT m.*
, g.type_0
, g.type_1
, g.type_2
FROM main m
LEFT
JOIN ( SELECT a.id
, GROUP_CONCAT(IF(c.type=0,c.code,NULL)) AS type_0
, GROUP_CONCAT(IF(c.type=1,c.code,NULL)) AS type_1
, GROUP_CONCAT(IF(c.type=2,c.code,NULL)) AS type_2
FROM main a
LEFT
JOIN events e
ON e.id = a.id
AND e.date BETWEEN a.start AND a.end
LEFT
JOIN codes c
ON c.code = e.code
AND c.type IN (0,1,2)
GROUP BY a.id
) g
ON g.id = m.id
我不确定其中任何一个都符合&#34;更优雅的方式&#34;或不。 (这两个都取决于id
中main
列为UNIQUE。第二个查询还依赖于id
非NULL。)
您可能需要考虑在ORDER BY
中添加GROUP_CONCAT
,以获得更确定的结果。如果没有理由返回&#34;重复&#34;还可以在DISTINCT
内包含GROUP_CONCAT
关键字。列表中code
的值,例如
GROUP_CONCAT(DISTINCT IF(c.type=0,c.code,NULL) ORDER BY 1)\
另请注意,GROUP_CONCAT
返回的值的最大长度仅限于group_concat_max_len
。