如何计算 SQL 中两个和的差

How to calculate the difference of two sums in SQL

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

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 来获得两个 itime 之间 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

它按预期工作。

现在,我想select和sum(count)根据sum(count) - sum(count)<--7-day-ago的区别。类似于 SELECT ... FROM ... WHERE ... HAVING c - c<--7-day-ago >= 100。但是我不知道怎么办。

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

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
;

根据需要进行调整。

也许您不想 return 区别,只需过滤 return 组。如果是这样,试试这个:

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
;

我刚才也遇到过类似的问题

请检查 SQLfiddle
要查看结果,请按按钮:首先- 构建模式,第二个:运行 sql

命名

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

  • period A = 您选择的时间段(介于 fromto 之间)
  • 时间段 B = 您选择的过去一周的时间段

问题

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

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

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

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;
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 │
└────────────┴─────┴─────┴──────┘