【发布时间】:2017-06-15 22:08:18
【问题描述】:
最好的方法是什么?
我将在下面进行描述,但这里有一个在 rextester.com 上的数据可供使用 - http://rextester.com/PXQOV60475
我有一个名为“案例”的表格,其中基本上包含有关维修工作的信息。 Case Manager 有一个名为“case_mgr”的字段,还有一个名为“case_mgr_first”的字段,因为 Case Manager 可以更改,因此它包含原始文件。 “who_last_call”还有另一个类似的字段,它是最后一次联系客户的用户。这些都包含用户名......虽然“case_mgr_first”和“who_last_call”可能为空(“case_mgr_first”是一个新字段,可能没有人调用)。
要继续维修工作,必须收到要维修的物品。收到后,设置字段“item_received_date”,否则为空。记录的创建日期也保存在“created_date”字段中。
因此,我们的目标是通过多种方式为用户找到接收百分比。我想在“created_date”之前的某个时间段内找到作为当前案例经理(“case_mgr”)、“case_mgr_first”和“who_last_call”的用户的接收率。
我已经对其中一个进行了查询,而且效果很好。
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 我错过了第二个查询的结果,该结果没有出现在第一个 where用户为 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_call”,那就太糟糕了)。最初的 2 个查询每个花费了大约 0.22 秒,而我第一次尝试 JOIN 花费了 0.50 秒。 “case_mgr”字段有索引,但没有“case_mgr_first”。
感谢任何帮助或建议!有没有更好的方法,或者我应该坚持单独的查询并将它们放在代码中?
【问题讨论】:
-
@Strawberry 我为这个问题做了很多搜索,发现有些人使用 sqlfiddle。我知道 jsfiddle,但没有意识到有一个 sqlfiddle。所以当我写这个问题的时候,我试着去那里做一个例子,但网站没有工作,尽管在不同的浏览器中重新加载了几次,但它完全是空白的。刚才检查了一下,谢天谢地,它看起来又可以工作了。
-
Sqlfiddle 更人性化,但我更喜欢 rextester。但是,无论哪种方式,这是链接答案中最不重要的部分。
-
-
@Strawberry 我把它放在一起 - rextester.com/PXQOV60475 。我还在下面的评论中为帕特里克的回答做了一个看起来不错的评论。
标签: mysql join full-outer-join