【问题标题】:Select from four mysql table with count and sum columns and where clause从具有 count 和 sum 列以及 where 子句的四个 mysql 表中选择
【发布时间】:2014-11-03 16:24:10
【问题描述】:

我的架构中有 5 个表。

首先是opn

| opnID | submitID | emailID |       opnDate       | invalidOPN |
+-------+----------+---------+---------------------+------------+
|   1   |    6     |    1    | 2014-10-15 11:45:50 |      2     |
|   2   |    6     |    2    | 2014-10-15 11:55:52 |      0     |
|   3   |    6     |    3    | 2014-10-15 12:41:52 |     10     |
|   4   |    7     |    2    | 2014-10-15 17:45:22 |      1     |
|   5   |    7     |    3    | 2014-10-16 00:45:55 |      5     |
|   6   |    6     |    5    | 2014-10-16 01:45:11 |      0     |

我也有clk:

| clkID| submitID | emailID |       clkDate        | invalidCLK |
+-------+----------+---------+---------------------+------------+
|   1   |    6     |    1    | 2014-10-15 11:45:55 |      1     |
|   2   |    6     |    2    | 2014-10-15 11:55:59 |      0     |
|   3   |    6     |    3    | 2014-10-15 12:42:52 |      5     |
|   4   |    7     |    3    | 2014-10-15 17:46:12 |      0     |
|   5   |    6     |    5    | 2014-10-16 00:46:55 |      0     |

users 表:

| userID | firstName | secondName |
+--------+-----------+------------+
|   1    |    john   |    smith   |
|   1    |   susan   |    bella   |

submission 表:

| submitID | userID |
+----------+--------+
|    6     |   1    |
|    7     |   2    |

我需要统计 opn.submitID 来获取打开次数,统计 clk.submitID 来获取每个用户的点击次数以及 invalidclk 和 invalidopn 的总数。

这是我的预期结果:

| userID | fName | sName | numberOfOpen | SUM(opn.invalidOPN) | numberOfClicks | SUM(clk.invalidCLK) |
+--------+-------+-------+--------------+---------------------+----------------+---------------------+
|   1    | john  | smith |      4       |          12         |        4       |         6           |
|   2    | susan | bella |      2       |           6         |        1       |         0           |

我尝试了这两个查询,但没有达到我需要的结果

SELECT users.userID, users.FirstName, users.SecondName, count(opn.submitID) as "Number of Opens", sum(opn.InvalidOPN) as "Number of invalid Opens"

FROM users 

RIGHT JOIN ( submission INNER JOIN opn ON opn.submitID = submission.submitID and OPNDate between "2013-10-01 00:00:00" AND "2014-10-31 23:59:59" ) ON submission.UserID = users.UserID   group by users.userID 

UNION

SELECT users.userID, users.FirstName, users.SecondName, count(clk.submitID) as "Number of clicks", sum(clk.InvalidCLK) as "Number of invalid clicks"
FROM users
RIGHT JOIN ( submission INNER JOIN clk ON clk.submitID = submission.submitID and CLKDate between "2013-10-01 00:00:00" AND "2014-10-31 23:59:59") ON submission.UserID = users.UserID  group by users.userID 

SELECT users.userID, users.FirstName, users.SecondName, count(opn.submitID) as "Number of Opens", sum(opn.InvalidOPN) as "Number of invalid Opens", count(clk.submitID) as "Number of clicks", sum(clk.InvalidCLK) as "Number of invalid clicks"

FROM users, submission, clk, opn 

where opn.submitID = submission.submitID and clk.submitID = submission.submitID 
And CLKDate between "2013-10-01 00:00:00" AND "2014-10-31 23:59:59" 
AND submission.UserID = users.UserID  group by users.userID

请帮助我,告诉我我需要改变什么。

【问题讨论】:

  • 正确加入万岁。不错。

标签: mysql join count group-by


【解决方案1】:

这样做的主要问题是,您需要将表相互连接起来,并获得 opn 和 clk 记录的每个组合。在这种情况下,您需要使用 COUNT(DISTINCT some_field_name) 来计算唯一值:-

SELECT users.UserId
        COUNT(DISTINCT opn.OPNID),
        COUNT(DISTINCT clk.CLKID)
FROM users
LEFT OUTER JOIN submission ON users.UserId = submission.UserId 
LEFT OUTER JOIN opn ON submission.SubmitID = opn.SubmitID 
LEFT OUTER JOIN clk ON submission.SubmitID = clk.SubmitID 
GROUP BY users.UserId

但是在这种情况下这并没有帮助,因为您还需要无效___字段的总和。

因此,我建议使用几个子查询,一个用于 clk,一个用于 opn。这些获取按用户 ID 分组的计数和总和。并将这些子查询的结果连接到 users 表中。

类似这样的:-

SELECT users.UserId,
        users.fName,
        users.sName,
        numberOfOpen,
        COALESCE(invalidopnsum, 0),
        numberOfClicks,
        COALESCE(invalidclksum, 0)
FROM users
LEFT OUTER JOIN
(
    SELECT submission.UserId, COUNT(opn.SubmitID) AS numberOfOpen, SUM(opn.InvalidOPN) AS invalidopnsum
    FROM submission 
    LEFT OUTER JOIN opn ON submission.SubmitID = opn.SubmitID 
    GROUP BY submission.UserId
) opn1
ON users.UserId = opn1.UserId 
LEFT OUTER JOIN
(
    SELECT submission.UserId, COUNT(clk.SubmitID) AS numberOfClicks, SUM(clk.InvalidCLK) AS invalidclksum
    FROM submission 
    LEFT OUTER JOIN clk ON submission.SubmitID = clk.SubmitID 
    GROUP BY submission.UserId
) clk1
ON users.UserId = clk1.UserId 

【讨论】:

  • 你只是在COALESCE(invalidopnsum, 0) 后面少了一个逗号。否则,这将返回正确的results.
【解决方案2】:

这比你想象的要容易。您需要做的就是将所有表连接在一起并使用一些聚合函数。您可以通过 userID 列上的提交加入用户,您可以使用 submitID 列将其加入 clk 和 opn 表。您可以使用 COUNT() 获取打开和点击次数,使用 SUM() 获取无效列的总数。但是,一次进行所有这些计算是行不通的,因为有些事实会重复,所以我建议您分别进行每个查询,然后加入它们。

查询如下所示:

SELECT t.userID, t.firstName, t.secondName, t.numOpen, t.totalInvalidOpen, w.numClick, w.totalInvalidClick
FROM (SELECT u.userID, u.firstName, u.secondName, COUNT(*) AS numOpen, SUM(o.invalidOPN) AS totalInvalidOpen
      FROM users u
      JOIN submission s ON s.userID = u.userID
      JOIN opn o ON o.submitID = s.submitID
      GROUP BY u.userID
      ) t
JOIN (SELECT u.userID, u.firstName, u.secondName, COUNT(*) AS numClick, SUM(c.invalidCLK) AS totalInvalidClick
      FROM users u
      JOIN submission s ON s.userID = u.userID
      JOIN clk c ON c.submitID = s.submitID
      GROUP BY u.userID
      ) w
ON w.userID = t.userID;

而且它有效!这是您的SQL Fiddle注意:您在问题中设置的结果不正确,因为用户 1 的无效打开总数仅为 12。

【讨论】:

  • 小问题是,如果用户在 opn 和 clk 表上都有记录,这只会带回用户。
  • 好收获。那么我应该像你一样离开加入用户表吗?
  • @Kickstart 我想我应该承认你的回答哈哈。如果我将我的更改为左连接,我将拥有与您的完全相同的。
  • 可能,但可能是 OP 只想要同时在 opn 和 clk 中的记录(从示例中不是 100% 清楚)。有了我的,我只需将外部联接更改为内部联接即可。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-28
  • 2014-10-23
  • 2015-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多