如何在SQL中计算两个和的差
Posted
技术标签:
【中文标题】如何在SQL中计算两个和的差【英文标题】:How to calculate the difference of two sums in SQL 【发布时间】:2021-11-12 05:48:33 【问题描述】:我正在使用 Grafana 显示来自 Clickhouse 的一些数据。数据来自包含itime
、count
和其他一些列的表。
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
s 之间的 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 合作。
【参考方案1】:
我之前也遇到过类似的问题
请查看SQLfiddle 查看结果按下按钮:第一个 - build schema,第二个:run sql
命名
我假设您希望在同一时间段 A 中选择 7 天后的时间段 B 进行比较(您需要更具体,您真正在寻找什么)。
期间 A = 您选择的时间段(from 和 to 之间) 期间 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 │
└────────────┴─────┴─────┴──────┘
【讨论】:
以上是关于如何在SQL中计算两个和的差的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 2035. 将数组分成两个数组并最小化数组和的差
leetcode 2035. 将数组分成两个数组并最小化数组和的差