如何计算 SQL 中两个和的差
How to calculate the difference of two sums in SQL
我正在使用 Grafana 来显示来自 Clickhouse 的一些数据。数据来自包含 itime
、count
和其他一些列的 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 = 您选择的时间段(介于 from 和 to 之间)
- 时间段 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 │
└────────────┴─────┴─────┴──────┘
我正在使用 Grafana 来显示来自 Clickhouse 的一些数据。数据来自包含 itime
、count
和其他一些列的 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 = 您选择的时间段(介于 from 和 to 之间)
- 时间段 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 │
└────────────┴─────┴─────┴──────┘