【问题标题】:Get COUNT() AND COUNT(DISTINCT()) values across 2 tables跨 2 个表获取 COUNT() AND COUNT(DISTINCT()) 值
【发布时间】:2016-02-01 21:36:49
【问题描述】:

我正在尝试从日期常见的联接表“Table2”中获取 COUNT(*) 以及“Table1”中的 COUNT(DISTINCT(CID)) 并按常见的年月分组:

Table1
---------------
cid |  date   | 
----|---------|
321 | 2016-01 |
----|---------|
423 | 2016-01 |
----|---------|
324 | 2016-01 |
----|---------|
546 | 2015-12 |
----|---------|

Table2
---------------
id  | dateEnq | 
----|---------|
3   | 2016-01 |
----|---------|
6   | 2016-01 |
----|---------|
24  | 2015-12 |
----|---------|
36  | 2015-12 |
----|---------|

MySQL 查询:

SELECT COUNT( DISTINCT (t1.cid) ) AS users,
SUBSTR(DATE(t1.date),1,7) AS month,
COUNT(t2.dateEnq) AS enquiries
FROM table1 t1
INNER JOIN table2 t2 ON SUBSTR(t2.dateEnq, 1, 7 ) = SUBSTR(t1.date, 1, 7 )
GROUP BY SUBSTR(DATE(t1.date),1,7)

这是我得到的结果,但是查询值是错误的,我认为它没有计算Table2中的值,它们应该是每行3、10、25。

如何从 Table2 中获取每月计数?

users | month    | enquiries|
------|----------|-----------
7237  | 2015-10  | 8374     |
12597 | 2015-11  | 30066    |
12980 | 2015-12  | 15514    |
11305 | 2016-01  | 128169   |

【问题讨论】:

    标签: mysql


    【解决方案1】:

    您的“计数”被夸大了,因为它是部分叉积。对于给定的月份,t1 中的每一行都与 t2 中同一个月的每一行相匹配。

    一种选择是在加入之前获取计数。例如,使用内联视图:

    SELECT c1.users
         , c1.month
         , c2.enquiries
      FROM ( SELECT COUNT(DISTINCT t1.cid)    AS `users`
                  , SUBSTR(DATE(t1.date),1,7) AS `month`
               FROM table1 t1
              GROUP BY SUBSTR(DATE(t1.date),1,7)
           ) c1
      JOIN ( SELECT COUNT(t2.dateEnq)         AS `enquiries`
                  , SUBSTR(DATE(t2.date),1,7) AS `month`
               FROM table2 t2 
              GROUP BY SUBSTR(DATE(t2.date),1,7)
           ) c2
        ON c2.month = c1.month
     ORDER BY c1.month
    

    这不是获得此结果的唯一方法(甚至不一定是最好的方法)。还有其他查询模式可以获得相同的结果。

    如果对于给定的monthenquiries 有可能为零,那么要返回该零计数,我们可以调整该查询使其成为外连接,然后替换任何 NULL 值(对于缺失的行) 在外部查询中为零:

    SELECT c1.users
         , c1.month
         , IFNULL(c2.enquiries,0) AS `enquiries`
      FROM ( SELECT COUNT(DISTINCT t1.cid)    AS `users`
                  , SUBSTR(DATE(t1.date),1,7) AS `month`
               FROM table1 t1
              GROUP BY SUBSTR(DATE(t1.date),1,7)
           ) c1
      LEFT
      JOIN ( SELECT COUNT(t2.dateEnq)         AS `enquiries`
                  , SUBSTR(DATE(t2.date),1,7) AS `month`
               FROM table2 t2 
              GROUP BY SUBSTR(DATE(t2.date),1,7)
           ) c2
        ON c2.month = c1.month
     ORDER BY c1.month
    

    【讨论】:

    • 啊,我明白你在说什么......你的第一个查询完美。
    • 是的,有可能是 0,谢谢,这也很好用。
    • ...我可以解释...因为内联视图查询保证具有唯一值 month(由于 GROUP BY 子句),两者之间的连接将具有(至多)给定月份每行。所以计数不会被夸大。您可以单独运行内联视图查询进行测试。一旦您了解了原始查询是如何生成膨胀计数的,问题实际上是我如何编写不生成部分叉积的 SQL 语句。这只是一种方法的示例。你可以把这个问题留着,看看你能不能得到更好的答案。
    • 不同查询的性能会受到基数、可用索引、查询计划的影响。当那些内联视图查询只返回 4 行时,连接速度非常快。但是,如果这些查询返回大量行,那么性能可能会快速下降。如果其中一组可能缺少一个月,则外部联接有效。如果其中任何一组缺少一个月,并且您希望查询返回零计数,则查询必须更精细一些。
    • inline view 查询是 SQL 工具带中的一个有用工具。它本质上与存储视图相同。这是FROM 子句中的一个查询,您从查询中引用结果集,就像它是一个表一样。 (MySQL 文档实际上将内联视图查询称为“派生表”。)也可以在查询的其他地方使用子查询。并非每个子查询都是内联视图查询。
    猜你喜欢
    • 2013-05-12
    • 1970-01-01
    • 2020-06-13
    • 2016-04-04
    • 2020-10-01
    • 1970-01-01
    • 2011-09-20
    • 2021-11-06
    • 1970-01-01
    相关资源
    最近更新 更多