我一直在搜索和查看SO帖子,但仍不确定如何完成此操作。
我有一个结果表,按(用户,截止日期)分组, 计算每个用户每个到期日的项目数。
以下是查询:
SELECT
userid as user,
nextduedate as due_date,
count(th.id) as services
FROM
`tblhosting` th
JOIN `tblcustomfieldsvalues` tcfv on th.userid = tcfv.relid
JOIN `tblclients` tc on th.userid = tc.id
WHERE
th.domainstatus = 'Active'
AND (th.nextduedate > date(DATE_SUB(curdate(), INTERVAL 5 day)) AND th.nextduedate < date(DATE_ADD(curdate(), INTERVAL 1 month)))
AND th.packageid NOT IN (132, 130, 129)
AND tcfv.fieldid = 55
AND tcfv.value = "on"
AND tc.separateinvoices = 0
GROUP BY userid, nextduedate
ORDER BY userid asc
结果:
| user | due_date | services |
|------|------------|----------|
| 77 | 2019-03-10 | 4 |
| 81 | 2019-03-05 | 23 |
| 99 | 2019-03-10 | 97 |
| 455 | 2019-03-13 | 9 |
| 478 | 2019-03-10 | 18 |
| 491 | 2019-03-03 | 1 |
| 491 | 2019-03-10 | 143 |
| 541 | 2019-03-02 | 2 |
| 541 | 2019-03-10 | 68 |
| 575 | 2019-03-02 | 46 |
用户491在03-03上有1个服务到期,在03-10上有143的服务到期。
我需要计算每个用户出现在列表中的次数,因为我正在寻找截止日期超过1个的用户。
从理论上讲,这实际上很容易,因为我可以像这样进行外部选择:
SELECT userid, COUNT(*)
FROM (inner select) a
GROUP BY a.userid
这会给我:
| user | count(userid)|
|------|--------------|
| 77 | 1 |
| 81 | 1 |
| 99 | 1 |
| 455 | 1 |
| 478 | 1 |
| 491 | 2 |
| 541 | 2 |
| 575 | 1 |
然后,我可以将该结果与原始结果连接起来,但是它需要运行两次查询。
Select * FROM
(
Inner Select a
LEFT JOIN
(
SELECT userid, COUNT(*) FROM
(inner select) a
GROUP BY a.userid
) b ON a.userid = b.userid
where x and y
) c
有了这个,我必须运行原始选择(作为内部选择),对其进行分组和计数(以获取计数),然后将其加入原始选择中,这效率很低并且会成倍增加运行时间。
为了提高效率,我想通过参考结果集来计算每个用户出现在原始结果中的次数。我需要为每个用户保留不同的截止日期,因此我不能简单地按用户ID分组。
理想情况下是这样的:
| user | due_date | services | counts |
|------|------------|----------|--------|
| 77 | 2019-03-10 | 4 | 1 |
| 81 | 2019-03-05 | 23 | 1 |
| 99 | 2019-03-10 | 97 | 1 |
| 455 | 2019-03-13 | 9 | 1 |
| 478 | 2019-03-10 | 18 | 1 |
| 491 | 2019-03-03 | 1 | 2 |
| 491 | 2019-03-10 | 143 | 2 |
| 541 | 2019-03-02 | 2 | 2 |
| 541 | 2019-03-10 | 68 | 2 |
| 575 | 2019-03-02 | 46 | 1 |
感谢您的帮助!
答案 0 :(得分:0)
对于MySQL 8.0,请使用窗口函数:
SELECT t.*, COUNT(*) OVER(PARTITION BY t.user) AS counts
FROM (
-- your query
) AS t
在旧版本的MySQL中,窗口函数和通用表表达式均不可用。我将在两个不同的(尽管几乎相同)子查询中计算两个聚合级别的结果,然后JOIN
来计算它们的结果:
SELECT t1.*, t2.counts
FROM (
SELECT userid as user, nextduedate as due_date, count(th.id) as services
FROM
`tblhosting` th
JOIN `tblcustomfieldsvalues` tcfv on th.userid = tcfv.relid
JOIN `tblclients` tc on th.userid = tc.id
WHERE
th.domainstatus = 'Active'
AND (th.nextduedate > date(DATE_SUB(curdate(), INTERVAL 5 day)) AND th.nextduedate < date(DATE_ADD(curdate(), INTERVAL 1 month)))
AND th.packageid NOT IN (132, 130, 129)
AND tcfv.fieldid = 55 and tcfv.value = "on"
AND tc.separateinvoices = 0
GROUP BY userid, nextduedate
) t1 INNER JOIN (
SELECT userid, count(th.id) as counts
FROM
`tblhosting` th
JOIN `tblcustomfieldsvalues` tcfv on th.userid = tcfv.relid
JOIN `tblclients` tc on th.userid = tc.id
WHERE
th.domainstatus = 'Active'
AND (th.nextduedate > date(DATE_SUB(curdate(), INTERVAL 5 day)) AND th.nextduedate < date(DATE_ADD(curdate(), INTERVAL 1 month)))
AND th.packageid NOT IN (132, 130, 129)
AND tcfv.fieldid = 55 and tcfv.value = "on"
AND tc.separateinvoices = 0
GROUP BY userid
) t2 ON t1.userid = t2.userid
ORDER BY t1.userid