MySQL在左连接上重复计算

时间:2012-11-21 17:23:50

标签: mysql sql count left-join

数据库结构

CREATE TABLE installs(
    id INT, PRIMARY KEY(id), 
    created DATETIME)

CREATE TABLE uninstalls(
    id INT, PRIMARY KEY(id),
    created DATETIME,
    install_id INT)

查询(“我与MySQL”)

SELECT DATE(installs.created),
  COUNT(installs.id),
  COUNT(uninstall.id)
FROM installs
LEFT JOIN uninstalls ON uninstalls.install_id = installs.id
GROUP BY DATE(installs.created)

“预期”输出

DATE(installs.created) | COUNT(installs.id) | COUNT(uninstalls.id) 
  2012-11-20           | *installs on date* | *uninstalls on date*

所以 - 我每天看一行,当天发生的安装/卸载次数。

问题

“安装”的数据每天都是正确的。但是每天“卸载”的数据可能不正确。

3 个答案:

答案 0 :(得分:4)

单独计算安装和卸载,为其中每个添加一个(零)列。然后将两者与UNION组合,再按日期分组,并为每个日期取最大值(以消除添加的零):

SELECT created as date, max(installs) as installs, max(uninstalls) as uninstalls
FROM
  (SELECT created, count(*) AS installs, 0 AS uninstalls
   FROM installs
   GROUP BY created
  UNION ALL
   SELECT created, 0 AS installs, count(*) AS uninstalls
   FROM uninstalls
   GROUP BY created) c
GROUP BY created
ORDER BY created

答案 1 :(得分:0)

发生此问题是因为您要链接安装和卸载。也就是说,您将在给定日期显示安装,并卸载以进行这些安装,而不是安装日期。

如果您想查看给定日期的每个事件的计数,您需要加入 date ,而不是安装ID。如果它是一个大型数据集,它将会非常慢(当您按该字段上的函数分组或加入时,优化器不能在字段上使用索引)。

SELECT DATE(installs.created),
  COUNT(installs.id),
  COUNT(uninstall.id)
FROM installs 
LEFT JOIN uninstalls ON DATE(uninstalls.created) = DATE(installs.created)
GROUP BY DATE(installs.created)

答案 2 :(得分:0)

创建包含安装和卸载所有日期的CTE,然后单独加入以安装和卸载表。

; WITH Dates AS
(
    SELECT DATE(created) AS created
    FROM
    (
        SELECT created
        FROM installs

            UNION ALL

        SELECT created
        FROM uninstalls
    ) a
    GROUP BY DATE(created)
)
, InstallCTE AS
(
    SELECT DATE(created) AS created
        , COUNT(*) AS c
    FROM installs
    GROUP BY DATE(created)
)
, UninstallCTE AS
(
    SELECT DATE(created) AS created
        , COUNT(*) AS c
    FROM uninstalls
    GROUP BY DATE(created)
)
SELECT d.created AS [date]
    , i.c AS install_count
    , u.c AS uninstall_count
FROM Dates d
LEFT JOIN InstallCTE i
    ON d.created = i.created
LEFT JOIN UninstallCTE u
    ON d.created = u.created