【问题标题】:MYSQL how to calculate the sum of a column within a date rangeMYSQL如何计算日期范围内列的总和
【发布时间】:2014-03-10 14:05:49
【问题描述】:

表格如下所示:

date       name    count
2013-1-1   Jack     20
2014-3-8   Jack     3
2014-3-1   Tom      1
2014-3-1   Jack     7
2014-2-28  Mary     4
2014-2-28  Tom      5

我想写一个查询来输出这个人的总数在过去 30 天内

eg. 
    Jack 10
    Tom  6
    Mary 4

执行此操作的最简单的 SQL 是什么?

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    你可以使用:

    SELECT name, SUM(count) FROM table_name WHERE date >= ( CURDATE() - INTERVAL 30 DAY ) GROUP BY name; 
    

    【讨论】:

    • 与其他答案不同,这不会将搜索字段放在函数中。相反,所有计算都在标量值上完成一次,因此允许使用索引。我希望我能在有其他答案的情况下给出这个 +2。
    • @MatBailie 这个怎么样:CURDATE() 之间的日期 - 间隔 30 天和 CURDATE()。与此答案相比,哪个更有效
    • @JoeyLi - 如果您可以在future 中有需要过滤掉的数据,是的,这就是这样做的方法。
    • @MatBailie 在效率方面,假设我们会有大规模的数据,并且会经常向表中插入新数据,哪个更好?
    • @JoeyLi - 唯一的区别在于您的建议会过滤掉未来的数据。如果您将来没有数据,为什么还要这样做呢?但是,如果您这样做,您将不会注意到差异。所有这些都假设您已经创建了合适的索引来允许搜索(例如name, date 或只是date
    【解决方案2】:

    更新:由@MatBailie查询为suggested

    mysql> SELECT
        ->    name, 
        ->    SUM(count) as total_count
        -> FROM table_name
        -> WHERE `date` >= DATE_SUB(NOW(), INTERVAL 30 day) AND `date` <= NOW()
        -> GROUP BY name    
        -> ;
    +------+-------------+
    | name | total_count |
    +------+-------------+
    | Jack |          10 |
    | Mary |           4 |
    | Tom  |           6 |
    +------+-------------+
    3 rows in set (0.02 sec)
    

    旧答案:

    试试:

    SELECT
       name, 
       SUM(count) as total_count
    FROM table_name
    WHERE ABS(DATEDIFF(`date` , now())) < 30
    GROUP BY name
    

    它正在工作:

    mysql> create table table_name (`date` datetime, name char(20), count int);
    Query OK, 0 rows affected (0.21 sec)
    
    mysql> insert into table_name values
        -> ('2013-1-1',   'Jack',     20),
        -> ('2014-3-8',   'Jack',     3),
        -> ('2014-3-1',   'Tom',      1),
        -> ('2014-3-1',   'Jack',     7),
        -> ('2014-2-28',  'Mary',     4),
        -> ('2014-2-28',  'Tom',      5);
    Query OK, 6 rows affected (0.12 sec)
    Records: 6  Duplicates: 0  Warnings: 0
    
    mysql> SELECT
        ->    name, 
        ->    SUM(count) as total_count
        -> FROM table_name
        -> WHERE ABS(DATEDIFF(`date` , now())) < 30
        -> GROUP BY name;
    +------+-------------+
    | name | total_count |
    +------+-------------+
    | Jack |          10 |
    | Mary |           4 |
    | Tom  |           6 |
    +------+-------------+
    3 rows in set (0.00 sec)
    

    编辑:根据评论:

    如果我想获得数量最多的前 2 个名字,即 Jack 和 Tom。如何做到这一点?

    使用ORDER BY DESCLIMIT,检查以下查询的结果。

    mysql> SELECT
        ->    name, 
        ->    SUM(count) as total_count
        -> FROM table_name
        -> WHERE `date` > DATE_SUB(NOW(), INTERVAL 30 day) and `date` < NOW()
        -> GROUP BY name
        -> ORDER BY total_count DESC
        -> LIMIT 2;
    +------+-------------+
    | name | total_count |
    +------+-------------+
    | Jack |          10 |
    | Tom  |           6 |
    +------+-------------+
    2 rows in set (0.03 sec)
    

    【讨论】:

    • WHERE ABS(DATEDIFF(date , now())) = 30 这行好像有问题。
    • @JoeyLi 我的名字后面有, 的错字,我还以为我没有检查它...好吧,我试试我的系统
    • 请注意:在函数中放置搜索字段(例如date)会混淆任何索引。对于 6 行数据无关紧要,但如果您曾经扩展到大量数据,则此模式是确定 不要这样做.
    • @GrijeshChauhan - 查找SARGable (Search ARGument = SARG),也可能查找right hand side calculations。原则是,如果您有一个索引,RDBMS 可以执行搜索并非常快速地仅识别满足条件(这是range-seek 的行。您的回答要求逐一检查每一行(这是full-table-scan
    • @GrijeshChauhan - 它们应该是 &gt;= AND &lt;= - 否则您可以过滤掉在 30 天前一天开始的午夜创建的结果,或者输入的结果 just now
    猜你喜欢
    • 2021-05-27
    • 1970-01-01
    • 1970-01-01
    • 2020-06-12
    • 2017-01-17
    • 1970-01-01
    • 2012-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多