【问题标题】:Using MySQL group_concat function with 'union' and 'in' in where clause在where子句中使用带有'union'和'in'的MySQL group_concat函数
【发布时间】:2017-01-03 08:50:33
【问题描述】:

我在 MySQL 中正确执行 group_concat() 函数时遇到问题。我的数据库中有实体,它们是受操作的对象。某些操作需要处理细节,这些细节作为处理的 id 提供。我的处理细节可能是一些主要处理的子进程,在 db 中这表示为

parent_id

在我的查询中,我向数据库询问所有子进程处理过的所有实体,这些子进程与我的起始实体的处理具有相同的 parent_id(我事先获得了包含所有信息的单个实体)。

在数据库中,where 子句如下所示:

where p.processing_id in
    (SELECT processing_id FROM processing_type_1 where parent_id in 
        (select parent_id from processing_type_1 where parent_id in (p.processing_id)))
        union all (SELECT processing_id FROM processing_type_2 where parent_id = 
            (select parent_id from processing_type_2 where parent_id in (p.processing_id)))

在我尝试在 select 子句中添加 group_concat() 之前,此子句按预期工作。实体上的每个操作都有分配给它的人员,我需要将所有人员分配给某些操作。

select 子句如下所示:

group_concat(distinct (select z.full_name from user z join entity_action ea on z.id = ea.personnel_id where ea.entity_id = e.id and ea.action_type = 'some_action' order by z.full_name) separator ', ') as action_personnel

这个查询在我添加之前不起作用

limit 1

在 group_concat() 中子查询的末尾。如果只分配一个人来执行该操作,那将不是问题,但不幸的是,情况并非如此。

我的问题是 - 有没有办法让这两个工作?

我的示例数据如下所示:

实体表

entity_id
1
2
3

entity_action 表

action_id|entity_id|  action_name|personnel_id|processing_id
        1|        1|'some action'|           1|           15
        2|        1|      'other'|           1|
        3|        1|    'another'|           2|
        4|        1|'some action'|           3|           17

加工表

processing_id|parent_id
           15|        5
           17|        5

如果我询问 parent_id 为 5 的所有处理,在这种情况下我想要的结果将是

entity_id|action_personnel
        1|             1,3

我的完整查询如下:

SELECT e.entity_id, 
group_concat(distinct (select z.full_name from user z join entity_action ea on z.id = ea.personnel_id where ea.entity_id = e.id and ea.action_type = 'some_action' order by z.full_name) separator ', ') as action_personnel
FROM enity e 
inner join entity_action ea on ea.entity_id = e.entity_id 
left outer join processing p on p.id = ea.entity_id
where
(1 IS null OR 
p.processing_id in
(SELECT processing_id FROM processing_type_1 where parent_id in 
    (select parent_id from processing_type_1 where parent_id in (p.processing_id)))
    union all (SELECT processing_id FROM processing_type_2 where parent_id = 
        (select parent_id from processing_type_2 where parent_id in (p.processing_id)))
)
group by e.entity_id;

【问题讨论】:

  • 请向我们展示示例表数据和您的预期输出。
  • 这看起来像一个疯狂的慢查询。嵌套IN 子选择可能是我能想象的最慢的事情。我想查询可以重新设计以使用JOIN 并且更快更方便。首先要改进的是,使用AS(别名)。
  • 你能显示完整的查询吗?我怀疑您尝试做的是针对 GROUP_CONCAT 的结果使用 IN。这将不起作用,因为 GROUP_CONCAT 返回一个字符串,而不是一个值列表。
  • @DanFromGermany 我知道这有点麻烦,但在它所处的状态下,它在大约 2-5 秒内处理大约 70k 行,这对于我的需要来说仍然相当快。
  • @Kickstart 抱歉,不能这样做。不过我可以向你保证,where 子句中没有任何对 group_concat() 的引用。

标签: mysql group-concat union-all where-in


【解决方案1】:

现在看多了。

我认为你的基本查询可以消除一些这样的 IN 子句(但这不会起作用)

SELECT e.entity_id, 
        GROUP_CONCAT((SELECT DISTINCT z.full_name FROM user z INNER JOIN entity_action ea ON z.id = ea.personnel_id WHERE ea.entity_id = e.id AND ea.action_type = 'some_action') ORDER BY full_name SEPARATOR ', ') AS action_personnel
FROM enity e 
INNER JOIN entity_action ea ON ea.entity_id = e.entity_id 
WHERE (1 IS NULL 
OR p.processing_id in
(
    SELECT processing_id 
    FROM processing_type_1 pt1_a
    INNER JOIN processing_type_1 pt1_b
    ON pt1_a.parent_id = pt1_b.parent_id 
    INNER processing p on p.id = ea.entity_id
    ON pt1_b.parent_id = p.processing_id
    UNION  
    SELECT processing_id pt2_a
    FROM processing_type_2 
    INNER JOIN processing_type_2 pt2_b
    ON pt2_a.parent_id = pt2_b.parent_id 
    INNER processing p on p.id = ea.entity_id
    ON pt2_b.parent_id = p.processing_id
)
)
GROUP BY e.entity_id;

看到这个,您在 GROUP_CONCAT 内的 SELECT 中有一个子查询。以前从未见过任何人尝试过此操作,并且该手册在 GROUP CONCAT 中没有提及任何有关此的内容。但是,当我使用这种语法时,MySQL 似乎很困惑,因为它有一个子查询在 SELECT 中返回多行,这会导致错误。这就是当您向子查询添加 LIMIT 1 时它会起作用的原因,因为它会强制它返回单行。

我清理后的查询也遇到了同样的问题。

也许可以清除它,只在主查询中对用户和实体操作进行连接,但不确定您的数据。

您可以做的是加入一个子查询,以将每个 entity_id 的所有全名组合在一起:-

SELECT e.entity_id, 
        sub1.action_personnel
FROM enity e 
INNER JOIN entity_action ea ON ea.entity_id = e.entity_id 
INNER JOIN 
(
    SELECT ea.entity_id,
            GROUP_CONCAT(DISTINCT z.full_name ORDER BY full_name SEPARATOR ', ') AS action_personnel
    FROM user z 
    INNER JOIN entity_action ea 
    ON z.id = ea.personnel_id 
    WHERE ea.entity_id = e.id 
    AND ea.action_type = 'some_action'
    GROUP BY ea.entity_id
) sub1
ON sub1.entity_id = e.id 
WHERE (1 IS NULL 
OR p.processing_id in
(
    SELECT processing_id 
    FROM processing_type_1 pt1_a
    INNER JOIN processing_type_1 pt1_b
    ON pt1_a.parent_id = pt1_b.parent_id 
    INNER processing p on p.id = ea.entity_id
    ON pt1_b.parent_id = p.processing_id
    UNION  
    SELECT processing_id pt2_a
    FROM processing_type_2 
    INNER JOIN processing_type_2 pt2_b
    ON pt2_a.parent_id = pt2_b.parent_id 
    INNER processing p on p.id = ea.entity_id
    ON pt2_b.parent_id = p.processing_id
)
)
GROUP BY e.entity_id;

【讨论】:

  • 在我的情况下,我需要将内部联接更改为左联接,因为实体可能没有附加任何处理。不过,连接内的子查询似乎正在工作,谢谢。
【解决方案2】:

尝试以下查询:

SELECT e.entity_id, 
GROUP_CONCAT(DISTINCT z.full_name ORDER BY z.full_name) SEPARATOR ', ') AS action_personnel
FROM enity e 
INNER JOIN entity_action ea ON ea.entity_id = e.entity_id 
LEFT OUTER JOIN processing p ON p.id = ea.entity_id
LEFT JOIN `user` z ON z.id = ea.personnel_id AND ea.action_type = 'some_action' 
WHERE
(1 IS NULL OR 
p.processing_id IN
(SELECT processing_id FROM processing_type_1 WHERE parent_id IN 
    (SELECT parent_id FROM processing_type_1 WHERE parent_id IN (p.processing_id)))
    UNION ALL (SELECT processing_id FROM processing_type_2 WHERE parent_id = 
        (SELECT parent_id FROM processing_type_2 WHERE parent_id IN (p.processing_id)))
)
GROUP BY e.entity_id;

【讨论】:

    猜你喜欢
    • 2011-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    • 2016-06-08
    • 2013-11-28
    • 2014-04-13
    • 1970-01-01
    相关资源
    最近更新 更多