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和窗口功能作为更好解决方案的选项,这些对我来说都是新的,并为我指明了学习/研究的新地方。另外,使用内部连接的完整解决方案比我提出的多个外部选择更好,所以请脱帽致敬,非常感谢您,先生!干杯