在 1 table 上合并多个 MySQL 查询(带分组依据)的结果
Combine results of multiple MySQL queries (w/ Group By) on 1 table
最好的方法是什么?
我将在下面进行描述,但这里是 rextester.com 数据的设置 -
http://rextester.com/PXQOV60475
我有一个名为 "cases" 的 table,其中基本上包含有关维修工作的信息。 Case Manager 有一个名为 "case_mgr" 的字段,还有一个 "case_mgr_first" 字段,因为 Case Manager 可以更改,因此它包含原始字段。 "who_last_called" 还有另一个类似的字段,它是最后联系客户的用户。这些都包含用户名...尽管 "case_mgr_first" 和 "who_last_called" 可能为空("case_mgr_first" 是一个新字段,可能没有人调用过)。
要继续修复工作,必须接收要修复的项目。收到后,字段 "item_received_date" 被设置,否则为空。 "created_date".
字段中还保存了记录的创建日期
因此,目标是通过多种方式为用户找到接收百分比。我想找到当前案例经理 ("case_mgr")、"case_mgr_first" 和 "who_last_called"... 的用户在特定时间段内的接收率 "created_date".
我已经对其中之一进行了查询,而且效果很好。
SELECT c.case_mgr AS case_mgr, COUNT(*) AS count_new,
SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END) AS count_recd,
SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END)*100/COUNT(*) AS percent_recd
FROM cases c WHERE (c.created_date >= '2017-05-01 00:00:00' AND c.created_date <= '2017-05-31 23:59:59')
GROUP BY c.case_mgr ORDER BY c.case_mgr ASC
这给了我一个结果-
+-----------+-----------+------------+--------------+
| case_mgr | count_new | count_recd | percent_recd |
+-----------+-----------+------------+--------------+
| bamm-bamm | 10 | 4 | 40.00 |
| barney | 105 | 43 | 40.95 |
| betty | 120 | 60 | 50.00 |
| fred | 139 | 54 | 38.85 |
| wilma | 97 | 56 | 57.73 |
+-----------+-----------+------------+--------------+
经过"case_mgr_first"时我也这样做。
SELECT c.case_mgr_first AS case_mgr_first, COUNT(*) AS count_new,
SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END) AS count_recd,
SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END)*100/COUNT(*) AS percent_recd
FROM cases c WHERE (c.created_date >= '2017-05-01 00:00:00' AND c.created_date <= '2017-05-31 23:59:59')
GROUP BY c.case_mgr_first ORDER BY c.case_mgr_first ASC
这给了我一个结果-
+----------------+-----------+------------+--------------+
| case_mgr_first | count_new | count_recd | percent_recd |
+----------------+-----------+------------+--------------+
| NULL | 137 | 62 | 45.26 |
| barney | 84 | 44 | 52.38 |
| betty | 72 | 37 | 51.39 |
| fred | 116 | 47 | 40.52 |
| wilma | 61 | 19 | 31.15 |
+----------------+-----------+------------+--------------+
(注意bamm-bamm出现在第一个结果中,第二个结果中没有,第二个结果中有一个NULL条目。)
我想要一个看起来像这样的组合结果(我删除了 count_new 和 count_recd 以便于阅读)-
+-----------+-----------------------+-----------------------------+
| user | percent_recd_case_mgr | percent_recd_case_mgr_first |
+-----------+-----------------------+-----------------------------+
| NULL | NULL | 45.26 |
| bamm-bamm | 40.00 | NULL |
| barney | 40.95 | 52.38 |
| betty | 50.00 | 51.39 |
| fred | 38.85 | 40.52 |
| wilma | 57.73 | 31.15 |
+-----------+-----------------------+-----------------------------+
通过使用子查询并加入这些子查询,我已经非常接近了,并且用户组合正确,但问题是使用 LEFT JOIN 我丢失了第二个查询的结果,该结果没有出现在首先是用户为 NULL 的地方,如果是 RIGHT JOIN,我会丢失第一个不在第二个中的结果。另外,它的查询持续时间似乎只是子查询的总和,这可能无法改进,我不确定。
这是我试过的查询-
SELECT * FROM
(
SELECT c.case_mgr AS case_mgr, SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END)*100/COUNT(*) AS percent_recd
FROM cases c WHERE (c.created_date >= '2017-05-01 00:00:00' AND c.created_date <= '2017-05-31 23:59:59')
GROUP BY c.case_mgr
) a
LEFT JOIN
(
SELECT c.case_mgr_first AS case_mgr_first, SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END)*100/COUNT(*) AS percent_recd
FROM cases c WHERE (c.created_date >= '2017-05-01 00:00:00' AND c.created_date <= '2017-05-31 23:59:59')
GROUP BY c.case_mgr_first
) b
ON a.case_mgr = b.case_mgr_first
ORDER BY a.case_mgr ASC
这是结果-
+-----------+-----------------------+----------------+-----------------------------+
| case_mgr | percent_recd_case_mgr | case_mgr_first | percent_recd_case_mgr_first |
+-----------+-----------------------+----------------+-----------------------------+
| bamm-bamm | 50.00 | NULL | NULL |
| barney | 40.95 | barney | 52.38 |
| betty | 50.00 | betty | 51.39 |
| fred | 38.85 | fred | 40.52 |
| wilma | 57.73 | wilma | 31.15 |
+-----------+-----------------------+----------------+-----------------------------+
我可以使用 2 个查询来执行此操作并将它们合并到代码中,但是将它们包含在一个查询中会很好,尤其是在可以以某种方式提高性能的情况下。
通过更多阅读,我明白这就像其他 SQL 中的 FULL OUTER JOIN 而在 MySQL 中不存在。它在 MySQL 中通过 LEFT JOIN 和 RIGHT JOIN 的 UNION 模拟。好的,现在我试过了,它确实有效,但是哇,它需要 0.92 秒(如果添加另一个字段,比如我在开头提到的 "who_last_called",那将是非常糟糕的)。最初的 2 个查询每个都花费了大约 0.22 秒,而我第一次尝试 JOIN 花费了 0.50 秒。 "case_mgr" 字段有索引,但 "case_mgr_first".
没有
如有任何帮助或建议,我们将不胜感激!有没有更好的方法,或者我应该坚持使用单个查询并将它们放在代码中?
我猜你可以想出一个解决方案,你可以做一个 UNION sub select 并在那个 sub select 上再次分组,但它不会很漂亮:
SELECT tmp.mgr,
SUM(tmp.percent_recd_case_mgr) AS percent_recd_case_mgr,
SUM(tmp.percent_recd_case_mgr_first) AS percent_recd_case_mgr
FROM ((
-- this the first part will basically contain the case_mgr data
SELECT
c.case_mgr AS mgr,
SUM(
CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END
)*100/COUNT(*) AS percent_recd_case_mgr,
0 AS percent_recd_case_mgr_first -- 0 as third column
FROM cases c
WHERE
c.created_date >= '2017-05-01 00:00:00'
AND c.created_date <= '2017-05-31 23:59:59'
GROUP BY c.case_mgr ORDER BY c.case_mgr ASC
) UNION (
-- And the second part contains the case_mgr_first data
SELECT
c.case_mgr_first AS mgr,
0 AS percent_recd_case_mgr, -- 0 as second column
SUM(
CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END
)*100/COUNT(*) AS percent_recd_case_mgr_first
FROM cases c
WHERE
c.created_date >= '2017-05-01 00:00:00'
AND c.created_date <= '2017-05-31 23:59:59'
GROUP BY c.case_mgr_first ORDER BY c.case_mgr_first ASC
)) AS tmp -- together both parts form a temp table and we sum again
-- over all records
GROUP BY tmp.mgr
ORDER BY tmp.mgr ASC;
最好的方法是什么?
我将在下面进行描述,但这里是 rextester.com 数据的设置 - http://rextester.com/PXQOV60475
我有一个名为 "cases" 的 table,其中基本上包含有关维修工作的信息。 Case Manager 有一个名为 "case_mgr" 的字段,还有一个 "case_mgr_first" 字段,因为 Case Manager 可以更改,因此它包含原始字段。 "who_last_called" 还有另一个类似的字段,它是最后联系客户的用户。这些都包含用户名...尽管 "case_mgr_first" 和 "who_last_called" 可能为空("case_mgr_first" 是一个新字段,可能没有人调用过)。
要继续修复工作,必须接收要修复的项目。收到后,字段 "item_received_date" 被设置,否则为空。 "created_date".
字段中还保存了记录的创建日期因此,目标是通过多种方式为用户找到接收百分比。我想找到当前案例经理 ("case_mgr")、"case_mgr_first" 和 "who_last_called"... 的用户在特定时间段内的接收率 "created_date".
我已经对其中之一进行了查询,而且效果很好。
SELECT c.case_mgr AS case_mgr, COUNT(*) AS count_new,
SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END) AS count_recd,
SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END)*100/COUNT(*) AS percent_recd
FROM cases c WHERE (c.created_date >= '2017-05-01 00:00:00' AND c.created_date <= '2017-05-31 23:59:59')
GROUP BY c.case_mgr ORDER BY c.case_mgr ASC
这给了我一个结果-
+-----------+-----------+------------+--------------+
| case_mgr | count_new | count_recd | percent_recd |
+-----------+-----------+------------+--------------+
| bamm-bamm | 10 | 4 | 40.00 |
| barney | 105 | 43 | 40.95 |
| betty | 120 | 60 | 50.00 |
| fred | 139 | 54 | 38.85 |
| wilma | 97 | 56 | 57.73 |
+-----------+-----------+------------+--------------+
经过"case_mgr_first"时我也这样做。
SELECT c.case_mgr_first AS case_mgr_first, COUNT(*) AS count_new,
SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END) AS count_recd,
SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END)*100/COUNT(*) AS percent_recd
FROM cases c WHERE (c.created_date >= '2017-05-01 00:00:00' AND c.created_date <= '2017-05-31 23:59:59')
GROUP BY c.case_mgr_first ORDER BY c.case_mgr_first ASC
这给了我一个结果-
+----------------+-----------+------------+--------------+
| case_mgr_first | count_new | count_recd | percent_recd |
+----------------+-----------+------------+--------------+
| NULL | 137 | 62 | 45.26 |
| barney | 84 | 44 | 52.38 |
| betty | 72 | 37 | 51.39 |
| fred | 116 | 47 | 40.52 |
| wilma | 61 | 19 | 31.15 |
+----------------+-----------+------------+--------------+
(注意bamm-bamm出现在第一个结果中,第二个结果中没有,第二个结果中有一个NULL条目。)
我想要一个看起来像这样的组合结果(我删除了 count_new 和 count_recd 以便于阅读)-
+-----------+-----------------------+-----------------------------+
| user | percent_recd_case_mgr | percent_recd_case_mgr_first |
+-----------+-----------------------+-----------------------------+
| NULL | NULL | 45.26 |
| bamm-bamm | 40.00 | NULL |
| barney | 40.95 | 52.38 |
| betty | 50.00 | 51.39 |
| fred | 38.85 | 40.52 |
| wilma | 57.73 | 31.15 |
+-----------+-----------------------+-----------------------------+
通过使用子查询并加入这些子查询,我已经非常接近了,并且用户组合正确,但问题是使用 LEFT JOIN 我丢失了第二个查询的结果,该结果没有出现在首先是用户为 NULL 的地方,如果是 RIGHT JOIN,我会丢失第一个不在第二个中的结果。另外,它的查询持续时间似乎只是子查询的总和,这可能无法改进,我不确定。
这是我试过的查询-
SELECT * FROM
(
SELECT c.case_mgr AS case_mgr, SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END)*100/COUNT(*) AS percent_recd
FROM cases c WHERE (c.created_date >= '2017-05-01 00:00:00' AND c.created_date <= '2017-05-31 23:59:59')
GROUP BY c.case_mgr
) a
LEFT JOIN
(
SELECT c.case_mgr_first AS case_mgr_first, SUM(CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END)*100/COUNT(*) AS percent_recd
FROM cases c WHERE (c.created_date >= '2017-05-01 00:00:00' AND c.created_date <= '2017-05-31 23:59:59')
GROUP BY c.case_mgr_first
) b
ON a.case_mgr = b.case_mgr_first
ORDER BY a.case_mgr ASC
这是结果-
+-----------+-----------------------+----------------+-----------------------------+
| case_mgr | percent_recd_case_mgr | case_mgr_first | percent_recd_case_mgr_first |
+-----------+-----------------------+----------------+-----------------------------+
| bamm-bamm | 50.00 | NULL | NULL |
| barney | 40.95 | barney | 52.38 |
| betty | 50.00 | betty | 51.39 |
| fred | 38.85 | fred | 40.52 |
| wilma | 57.73 | wilma | 31.15 |
+-----------+-----------------------+----------------+-----------------------------+
我可以使用 2 个查询来执行此操作并将它们合并到代码中,但是将它们包含在一个查询中会很好,尤其是在可以以某种方式提高性能的情况下。
通过更多阅读,我明白这就像其他 SQL 中的 FULL OUTER JOIN 而在 MySQL 中不存在。它在 MySQL 中通过 LEFT JOIN 和 RIGHT JOIN 的 UNION 模拟。好的,现在我试过了,它确实有效,但是哇,它需要 0.92 秒(如果添加另一个字段,比如我在开头提到的 "who_last_called",那将是非常糟糕的)。最初的 2 个查询每个都花费了大约 0.22 秒,而我第一次尝试 JOIN 花费了 0.50 秒。 "case_mgr" 字段有索引,但 "case_mgr_first".
没有如有任何帮助或建议,我们将不胜感激!有没有更好的方法,或者我应该坚持使用单个查询并将它们放在代码中?
我猜你可以想出一个解决方案,你可以做一个 UNION sub select 并在那个 sub select 上再次分组,但它不会很漂亮:
SELECT tmp.mgr,
SUM(tmp.percent_recd_case_mgr) AS percent_recd_case_mgr,
SUM(tmp.percent_recd_case_mgr_first) AS percent_recd_case_mgr
FROM ((
-- this the first part will basically contain the case_mgr data
SELECT
c.case_mgr AS mgr,
SUM(
CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END
)*100/COUNT(*) AS percent_recd_case_mgr,
0 AS percent_recd_case_mgr_first -- 0 as third column
FROM cases c
WHERE
c.created_date >= '2017-05-01 00:00:00'
AND c.created_date <= '2017-05-31 23:59:59'
GROUP BY c.case_mgr ORDER BY c.case_mgr ASC
) UNION (
-- And the second part contains the case_mgr_first data
SELECT
c.case_mgr_first AS mgr,
0 AS percent_recd_case_mgr, -- 0 as second column
SUM(
CASE WHEN c.item_received_date IS NOT NULL THEN 1 ELSE 0 END
)*100/COUNT(*) AS percent_recd_case_mgr_first
FROM cases c
WHERE
c.created_date >= '2017-05-01 00:00:00'
AND c.created_date <= '2017-05-31 23:59:59'
GROUP BY c.case_mgr_first ORDER BY c.case_mgr_first ASC
)) AS tmp -- together both parts form a temp table and we sum again
-- over all records
GROUP BY tmp.mgr
ORDER BY tmp.mgr ASC;