【问题标题】:How to calculate the difference of two sums in SQL如何在SQL中计算两个和的差
【发布时间】:2021-11-12 05:48:33
【问题描述】:

我正在使用 Grafana 显示来自 Clickhouse 的一些数据。数据来自包含itimecount 和其他一些列的表。

id  method   count        itime
1    aaa      12     2021-07-20 00:07:06
2    bbb      9      2021-07-20 00:07:06
3    ccc      7      2021-07-20 00:07:07
...

现在我可以执行以下 SQL 来获得两个 itimes 之间的 count 之和:

SELECT toUnixTimestamp(toStartOfMinute(itime)) * 1000 as t,
       method,
       sum(count) as c
FROM me.my_table
WHERE itime BETWEEN toDateTime(1631870605) AND toDateTime(1631874205)
      and method like 'a%'
GROUP BY method, t
HAVING c > 500
ORDER BY t

它按预期工作。

现在,我想根据sum(count) - sum(count)<--7-day-ago之间的差异选择sum(count)。像SELECT ... FROM ... WHERE ... HAVING c - c<--7-day-ago >= 100 这样的东西。但我不知道怎么做。

【问题讨论】:

  • 您能否简化您的查询并删除您创建的函数(如果我们不需要它们)?另外,您能否给我们一些更多数据(相关数据)和该数据的预期结果(因为您说 7 天前......并且示例都在同一天......)
  • @VBoka 好吧,事实上我正在与 Grafana 和 Clickhouse 合作......好吧,除了 itime 发生了变化之外,数据就是这样。我确信它存储了大量数据,包括 7 天前的数据。
  • @Akina 我是 DB 的新手。我以为他们都一样。事实上,我正在与 Grafana 和 Clickhouse 合作。

标签: sql grafana clickhouse having


【解决方案1】:

我之前也遇到过类似的问题

请查看SQLfiddle
查看结果按下按钮:第一个 - build schema,第二个:run sql

命名

我假设您希望在同一时间段 A 中选择 7 天后的时间段 B 进行比较(您需要更具体,您真正在寻找什么)。

  • 期间 A = 您选择的时间段(fromto 之间)
  • 期间 B = 您选择的过去一周内的时间段

问题

如果我理解正确的话,这是一个非常微妙的问题。
您的示例在周期 A 内按分钟分组。这意味着,对于周期 B 中有数据的每一分钟,您确实需要周期 A 中的数据,否则您将忽略所选周期内的周期 B 数据。

正如您在 sqlfiddle 中看到的,我创建了两个查询字符串。第一个正在工作,但忽略了 B 数据。第二个进行右连接(遗憾的是 mysql 不支持完全外连接以在一个表中显示所有内容)并显示 2 个被忽略的条目。

这甚至使情况变得更糟,因为您也按方法分组。
(在这种情况下,您必须更改连接的最后一行并添加:)

as b on a.unix_itime = b.unix_itime and a.method = b.method

这意味着,您需要每个选定的方法和周期的分钟数据。

如果你只按方法而不是时间分组会更好,因为你已经使用时间条件(周期 A)来保持它的小。
或按小时或按天加大步数..

此代码应该适合您的环境(mysql 不支持 toUnixTimestamp、toStartOfMinute、toDateTime):

SELECT 
    a.unix_itime * 1000 as t,
    a.method,
    a.sum AS c,
    b.sum AS c2,
    ifnull(a.sum,0) - ifnull(b.sum,0) as diff,
    
FROM (select method, sum(count) as sum, toUnixTimestamp(toStartOfMinute(itime)) as unix_itime
      from my_table
      WHERE method like 'a%' and
          itime BETWEEN toDateTime(1631870605) 
                    AND toDateTime(1631874205)
      GROUP BY method, unix_itime) 
          as a

  LEFT JOIN (select method, sum(count) as sum, toUnixTimestamp(toStartOfMinute(itime + INTERVAL 7 DAY)) as unix_itime
            from my_table
            WHERE method like 'a%' and
                itime BETWEEN toDateTime(1631870605)- INTERVAL 7 DAY 
                          AND toDateTime(1631874205)- INTERVAL 7 DAY
            GROUP BY method, unix_itime) 
                as b on a.unix_itime = b.unix_itime and a.method = b.method

ORDER BY a.unix_itime;

【讨论】:

    【解决方案2】:

    逻辑有点模棱两可,但这可能会产生上述一种可能的含义。如果您仍想返回整体 SUM(count),只需将其添加到选择列表中即可。

    SELECT toUnixTimestamp(toStartOfMinute(itime)) * 1000 AS t
         , method
         , SUM(count) AS c
         , SUM(count) - SUM(CASE WHEN itime < current_date - INTERVAL 7 DAY THEN count END) AS c2
      FROM me.my_table
     WHERE method like 'a%'
     GROUP BY method, t
    HAVING c2 >= 100
     ORDER BY t
    ;
    

    根据需要进行调整。

    也许您不想返回差异,只是过滤返回的组。如果是这样,试试这个:

    SELECT toUnixTimestamp(toStartOfMinute(itime)) * 1000 AS t
         , method
         , SUM(count) AS c
      FROM me.my_table
     WHERE method like 'a%'
     GROUP BY method, t
    HAVING SUM(count) - SUM(CASE WHEN itime < current_date - INTERVAL 7 DAY THEN count END) >= 100
     ORDER BY t
    ;
    

    【讨论】:

      【解决方案3】:
      create table test(D Date, Key Int64, Val Int64) Engine=Memory;
      
      insert into test select today(), number, 100 from numbers(5);
      
      insert into test select today()-7, number, 110 from numbers(5);
      
      
      select sx.2 d1, Key, sumIf(sx.1, D=sx.2) s, sumIf(sx.1, D!=sx.2) s1 from (
      select D, Key, arrayJoin([(s, D), (s, D + interval 7 day)]) sx
      from (select D, Key, sum(Val) s from test group by D, Key)
      )group by d1, Key
      order by d1, Key;
      
      ┌─────────d1─┬─Key─┬───s─┬──s1─┐
      │ 2021-09-10 │   0 │ 110 │   0 │
      │ 2021-09-10 │   1 │ 110 │   0 │
      │ 2021-09-10 │   2 │ 110 │   0 │
      │ 2021-09-10 │   3 │ 110 │   0 │
      │ 2021-09-10 │   4 │ 110 │   0 │
      │ 2021-09-17 │   0 │ 100 │ 110 │
      │ 2021-09-17 │   1 │ 100 │ 110 │
      │ 2021-09-17 │   2 │ 100 │ 110 │
      │ 2021-09-17 │   3 │ 100 │ 110 │
      │ 2021-09-17 │   4 │ 100 │ 110 │
      │ 2021-09-24 │   0 │   0 │ 100 │
      │ 2021-09-24 │   1 │   0 │ 100 │
      │ 2021-09-24 │   2 │   0 │ 100 │
      │ 2021-09-24 │   3 │   0 │ 100 │
      │ 2021-09-24 │   4 │   0 │ 100 │
      └────────────┴─────┴─────┴─────┘
      
      SELECT
          D,
          Key,
          Val,
          any(Val) OVER (PARTITION BY Key ORDER BY D ASC RANGE BETWEEN 7 PRECEDING AND 7 PRECEDING) Val1
      FROM test
      
      ┌──────────D─┬─Key─┬─Val─┬─Val1─┐
      │ 2021-09-10 │   0 │ 110 │    0 │
      │ 2021-09-17 │   0 │ 100 │  110 │
      │ 2021-09-10 │   1 │ 110 │    0 │
      │ 2021-09-17 │   1 │ 100 │  110 │
      │ 2021-09-10 │   2 │ 110 │    0 │
      │ 2021-09-17 │   2 │ 100 │  110 │
      │ 2021-09-10 │   3 │ 110 │    0 │
      │ 2021-09-17 │   3 │ 100 │  110 │
      │ 2021-09-10 │   4 │ 110 │    0 │
      │ 2021-09-17 │   4 │ 100 │  110 │
      └────────────┴─────┴─────┴──────┘
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多