MYSQL:计算一个值在结果中出现的次数,而不递归运行查询
我一直在谷歌上搜索和查看这么多帖子,仍然不确定如何做到这一点 我有一个结果表,按用户、截止日期分组, 计算每个用户每个到期日的项目数 以下是查询:MYSQL:计算一个值在结果中出现的次数,而不递归运行查询,mysql,sql,join,group-by,count,Mysql,Sql,Join,Group By,Count,我一直在谷歌上搜索和查看这么多帖子,仍然不确定如何做到这一点 我有一个结果表,按用户、截止日期分组, 计算每个用户每个到期日的项目数 以下是查询: SELECT userid as user, nextduedate as due_date, count(th.id) as services FROM `tblhosting` th JOIN `tblcustomfieldsvalues` tcfv on th.userid = tcfv.re
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
用户491有1项服务于03-03到期,143项服务于03-10到期
我需要计算每个用户在列表中出现的次数,因为我专门寻找到期日超过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 |
谢谢你的帮助 在MySQL 8.0中,使用窗口函数:
SELECT t.*, COUNT(*) OVER(PARTITION BY t.user) AS counts
FROM (
-- your query
) AS t
对于较旧版本的MySQL,窗口函数和公共表表达式都不可用。我将在两个不同但几乎相同的子查询中计算两个聚合级别的结果,然后合并它们的结果:
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
在MySQL 8.0中,使用窗口函数:
SELECT t.*, COUNT(*) OVER(PARTITION BY t.user) AS counts
FROM (
-- your query
) AS t
对于较旧版本的MySQL,窗口函数和公共表表达式都不可用。我将在两个不同但几乎相同的子查询中计算两个聚合级别的结果,然后合并它们的结果:
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
哇,这让我为MySQL 8.0提供的服务感到非常兴奋,谢谢!我应该提到,我们的环境需要5.7版本,在我们的第三方软件支持8.0版本之前是不可能升级的:/@Andrew:太糟糕了。。。好的,我用一个MySQL<8.0的解决方案更新了我的答案,这个解决方案不那么优雅,但应该可以工作。这就是我担心的,谢谢你的更新。我非常感谢您提到CTE和窗口功能作为更好解决方案的选项,这些对我来说都是新的,并为我指明了学习/研究的新地方。另外,使用内部连接的完整解决方案比我提出的多个外部选择更好,所以请脱帽致敬,非常感谢您,先生!干杯,这让我为MySQL 8.0提供的服务感到非常兴奋,谢谢!我应该提到,我们的环境需要5.7版本,在我们的第三方软件支持8.0版本之前是不可能升级的:/@Andrew:太糟糕了。。。好的,我用一个MySQL<8.0的解决方案更新了我的答案,这个解决方案不那么优雅,但应该可以工作。这就是我担心的,谢谢你的更新。我非常感谢您提到CTE和窗口功能作为更好解决方案的选项,这些对我来说都是新的,并为我指明了学习/研究的新地方。另外,使用内部连接的完整解决方案比我提出的多个外部选择更好,所以请脱帽致敬,非常感谢您,先生!干杯