【问题标题】:MySQL: Any good way to get cumulative counts and diff counts?MySQL:获得累积计数和差异计数的任何好方法?
【发布时间】:2017-12-06 08:52:32
【问题描述】:

假设我有以下数据集。

+--------------------+
| item_id count date |
+--------------------+
| 000 10 2017-11-01  |
| 001 15 2017-11-01  |
| 002 2 2017-11-01   |
| 003 100 2017-11-01 |
| 000 20 2017-11-02  |
| 001 20 2017-11-02  |
| 002 22 2017-11-02  |
| 003 101 2017-11-02 |
| 000 30 2017-11-03  |
| 001 25 2017-11-03  |
| 002 42 2017-11-03  |
| 003 102 2017-11-03 |
| 000 40 2017-11-04  |
| 001 30 2017-11-04  |
| 002 62 2017-11-04  |
| 003 103 2017-11-04 |
+--------------------+

有没有什么方法可以获取两个任意日期之间每一天的累积计数和差异计数?
(对于 diff 计数,如果选择的日期是 2017-11-01 和 2017-11-04,则第一个 diff count(2017-11-01) 不必包含在最终 SQL 结果中,因为没有该日期之前的可用数据)

以下两个表是预期的 SQL 结果。

累计次数

+--------------------+
| item_id count date |
+--------------------+
| 000 10 2017-11-01  |
| 000 30 2017-11-02  |
| 000 60 2017-11-03  |
| 000 100 2017-11-03 |
| 001 15 2017-11-01  |
| 001 35 2017-11-02  |
| 001 60 2017-11-03  |
| 001 90 2017-11-04  |
| 002 2 2017-11-01   |
| 002 24 2017-11-02  |
| 002 66 2017-11-03  |
| 002 128 2017-11-04 |
| 003 100 2017-11-01 |
| 003 201 2017-11-02 |
| 003 303 2017-11-03 |
| 003 406 2017-11-04 |
+--------------------+

差异计数

+--------------------+
| item_id count date |
+--------------------+
| 000 10 2017-11-02  |
| 000 10 2017-11-03  |
| 000 10 2017-11-04  |
| 001 5 2017-11-02   |
| 001 5 2017-11-03   |
| 001 5 2017-11-04   |
| 002 20 2017-11-02  |
| 002 20 2017-11-03  |
| 002 20 2017-11-04  |
| 003 1 2017-11-02   |
| 003 1 2017-11-03   |
| 003 1 2017-11-04   |
+--------------------+

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    由于MySQL不支持windowsOLAP函数(最新版本除外),所以可以使用变量。

    累计总和:

    set @item_id := 0;
    set @val := 0;
    
    select t.item_id, t.count, t.date, t.CSUM as CummulativeSUM
    from (
    select t1.*, 
           @val := if(@item_id=item_id, @val + t1.count, t1.count) as CSUM,
           @item_id := item_id
    from table1 t1
    order by t1.item_id, t1.date
        ) t;
    

    结果:

    +---------+-------+---------------------+----------------+
    | item_id | count |        date         | CummulativeSUM |
    +---------+-------+---------------------+----------------+
    |       0 |    10 | 01.11.2017 00:00:00 |             10 |
    |       0 |    20 | 02.11.2017 00:00:00 |             30 |
    |       0 |    30 | 03.11.2017 00:00:00 |             60 |
    |       0 |    40 | 04.11.2017 00:00:00 |            100 |
    |       1 |    15 | 01.11.2017 00:00:00 |             15 |
    |       1 |    20 | 02.11.2017 00:00:00 |             35 |
    |       1 |    25 | 03.11.2017 00:00:00 |             60 |
    |       1 |    30 | 04.11.2017 00:00:00 |             90 |
    |       2 |     2 | 01.11.2017 00:00:00 |              2 |
    |       2 |    22 | 02.11.2017 00:00:00 |             24 |
    |       2 |    42 | 03.11.2017 00:00:00 |             66 |
    |       2 |    62 | 04.11.2017 00:00:00 |            128 |
    |       3 |   100 | 01.11.2017 00:00:00 |            100 |
    |       3 |   101 | 02.11.2017 00:00:00 |            201 |
    |       3 |   102 | 03.11.2017 00:00:00 |            303 |
    |       3 |   103 | 04.11.2017 00:00:00 |            406 |
    +---------+-------+---------------------+----------------+
    

    Cumulative SUM DEMO


    差异计数:

    set @item_id1 := 0;
    set @val1 := 0; 
    set @count := 0;
    
    select t.item_id, t.count, t.date, t.CSUM as diffSUM
    from (
    select t1.*, 
           @val1 := if(@item_id1=item_id, t1.count - @count, t1.count) as CSUM,
           @item_id1 := item_id,
           @count := count
    from table1 t1
    order by t1.item_id, t1.date
        ) t
    where count <> csum;
    

    结果:

    +---------+-------+---------------------+-----------+
    | item_id | count |        date         | diffCount |
    +---------+-------+---------------------+-----------+
    |       0 |    20 | 02.11.2017 00:00:00 |        10 |
    |       0 |    30 | 03.11.2017 00:00:00 |        10 |
    |       0 |    40 | 04.11.2017 00:00:00 |        10 |
    |       1 |    20 | 02.11.2017 00:00:00 |         5 |
    |       1 |    25 | 03.11.2017 00:00:00 |         5 |
    |       1 |    30 | 04.11.2017 00:00:00 |         5 |
    |       2 |    22 | 02.11.2017 00:00:00 |        20 |
    |       2 |    42 | 03.11.2017 00:00:00 |        20 |
    |       2 |    62 | 04.11.2017 00:00:00 |        20 |
    |       3 |   101 | 02.11.2017 00:00:00 |         1 |
    |       3 |   102 | 03.11.2017 00:00:00 |         1 |
    |       3 |   103 | 04.11.2017 00:00:00 |         1 |
    +---------+-------+---------------------+-----------+
    

    DIFF Count DEMO

    【讨论】:

    • 感谢您的意见。累积的一个有效,但另一个抛出一个错误,说“'字段列表'中的未知列'计数'”。我不知道如何解决这个错误...
    • @d.s:请检查随附的演示。它就像一个魅力:-)
    • 想通了!
    【解决方案2】:

    看看这个,看看它是否有用。这是 ms sql server 方法,但希望足够相似以提供帮助。

    DECLARE @Tbl AS TABLE (item CHAR(3)
                          ,count INT
                          ,date DATE
                          )
    INSERT  INTO @Tbl
            (item, count, date)
    VALUES  ('000', 10, '2017-11-01'),
            ('001', 15, '2017-11-01'),
            ('002', 2, '2017-11-01'),
            ('003', 100, '2017-11-01'),
            ('000', 20, '2017-11-02'),
            ('001', 20, '2017-11-02'),
            ('002', 22, '2017-11-02'),
            ('003', 101, '2017-11-02'),
            ('000', 30, '2017-11-03'),
            ('001', 25, '2017-11-03'),
            ('002', 42, '2017-11-03'),
            ('003', 102, '2017-11-03'),
            ('000', 40, '2017-11-04'),
            ('001', 30, '2017-11-04'),
            ('002', 62, '2017-11-04'),
            ('003', 103, '2017-11-04');
    WITH    cte
              AS (SELECT    *
                  ,         ROW_NUMBER() OVER (PARTITION BY item ORDER BY date) RN
                  FROM      @Tbl
                 )
        SELECT  A.item
         ,      A.count
         ,      A.date
         ,      C.Cume
        FROM    cte A
        CROSS APPLY (SELECT SUM(count) Cume
                     FROM   cte B
                     WHERE  A.item = B.item
                            AND A.RN >= B.RN
                    ) C
    

    这是一个通用示例,说明如何根据您的数据获取累计总数。添加日期范围应该很简单。使用行号技术,您可以将先前的总和替换为与先前的差。

    如果您看完后仍然卡住,请告诉我,我也可以编写代码,但如果您能理解这里做了什么并应用您自己的解决方案,那就更好了。

    【讨论】:

    • MySQL(最新版本除外)不支持OLAP功能:-)
    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 2017-05-15
    • 1970-01-01
    • 2019-04-17
    相关资源
    最近更新 更多