如何按DATE_FORMAT(date,'%Y-%m-%d')求和,限制20个求和(每天),如果大于20求和剩余值?
how to sum value by DATE_FORMAT(date,'%Y-%m-%d'),the limit 20 sum(day by day), and sum remaining value if greater than 20?
如何通过DATE_FORMAT(date,'%Y-%m-%d')
对值求和并识别前20行数据(按数据desc排序),如果大于20则对剩余值求和,否则为0?假设我的数据低于 SQL,怎么办?非常感谢您的任何建议。
SELECT SUM(value), id, DATE_FORMAT(date,'%Y-%m-%d')
FROM test_table
GROUP BY id, DATE_FORMAT(date,'%Y-%m-%d')
sum(value) id DATE_FORMAT(date,'%Y-%m-%d')
--------------------------------------------
64.98 123456 2021-01-01
64.98 123456 2021-01-02
64.98 123456 2021-01-03
64.98 123456 2021-01-04
64.98 123456 2021-01-05
64.98 123456 2021-01-06
72.34 123456 2021-01-07
64.98 123456 2021-01-08
64.98 123456 2021-01-09
103.80 123456 2021-01-10
64.98 123456 2021-01-11
64.98 123456 2021-01-12
64.98 123456 2021-01-13
64.98 123456 2021-01-14
64.98 123456 2021-01-15
64.98 123456 2021-01-16
64.98 123456 2021-01-17
64.98 123456 2021-01-18
64.98 123456 2021-01-19
64.98 123456 2021-01-20
64.98 123456 2021-01-21
64.98 123456 2021-01-22
64.98 123456 2021-01-23
64.98 123456 2021-01-24
144.98 123456 2021-01-25
64.98 123456 2021-01-26
64.98 123456 2021-01-27
64.98 123456 2021-01-28
64.98 123456 2021-01-29
64.98 123456 2021-01-30
64.98 123456 2021-01-31
64.98 123456 2021-02-01
64.98 123456 2021-02-02
64.98 123456 2021-02-03
64.98 123456 2021-02-04
720.92 123456 2021-02-05
66.98 123456 2021-02-06
66.98 123456 2021-02-07
66.98 123456 2021-02-08
64.98 123456 2021-02-09
64.98 123456 2021-02-10
64.98 223456 2021-01-20
54.98 223456 2021-01-21
......................................
我需要如下输出:
id day_1 day_2 ..... day_20 day_other
--------------------------------------------
123456 64.98 64.98 ..... 234.67 2342.12
223456 64.98 64.98 ..... 234.67 2342.12
终于通过下面SQL解决了这个问题,非常感谢FanoFN的
SELECT id,
SUM(CASE WHEN rn = 1 THEN vals ELSE 0 END) AS 'day_1',
SUM(CASE WHEN rn = 2 THEN vals ELSE 0 END) AS 'day_2',
SUM(CASE WHEN rn = 3 THEN vals ELSE 0 END) AS 'day_3',
SUM(CASE WHEN rn = 4 THEN vals ELSE 0 END) AS 'day_4',
SUM(CASE WHEN rn = 5 THEN vals ELSE 0 END) AS 'day_5',
SUM(CASE WHEN rn = 6 THEN vals ELSE 0 END) AS 'day_6',
SUM(CASE WHEN rn = 7 THEN vals ELSE 0 END) AS 'day_7',
SUM(CASE WHEN rn = 8 THEN vals ELSE 0 END) AS 'day_8',
SUM(CASE WHEN rn = 9 THEN vals ELSE 0 END) AS 'day_9',
SUM(CASE WHEN rn = 10 THEN vals ELSE 0 END) AS 'day_10',
SUM(CASE WHEN rn = 11 THEN vals ELSE 0 END) AS 'day_11',
SUM(CASE WHEN rn = 12 THEN vals ELSE 0 END) AS 'day_12',
SUM(CASE WHEN rn = 13 THEN vals ELSE 0 END) AS 'day_13',
SUM(CASE WHEN rn = 14 THEN vals ELSE 0 END) AS 'day_14',
SUM(CASE WHEN rn = 15 THEN vals ELSE 0 END) AS 'day_15',
SUM(CASE WHEN rn = 16 THEN vals ELSE 0 END) AS 'day_16',
SUM(CASE WHEN rn = 17 THEN vals ELSE 0 END) AS 'day_17',
SUM(CASE WHEN rn = 18 THEN vals ELSE 0 END) AS 'day_18',
SUM(CASE WHEN rn = 19 THEN vals ELSE 0 END) AS 'day_19',
SUM(CASE WHEN rn = 20 THEN vals ELSE 0 END) AS 'day_20',
SUM(CASE WHEN rn > 20 THEN vals ELSE 0 END) AS 'day_others'
FROM
(SELECT SUM(value) AS vals, id, DATE_FORMAT(date,'%Y-%m-%d') AS dt,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY dt DESC) AS rn
FROM test_table
GROUP BY id, dt) v
GROUP BY id;
注意: 不幸的是,此解决方案中的部分组件不适用于旧的 MySQL 版本;正如 OP 提到的 ,她正在使用 MySQL 5.7.
我明白了,那样的话你可以稍微升级一下查询。让我们考虑一下,条件可能会以某种方式更改为前 30 行数据,那么您可能希望使用准备好的语句,这样您就不需要继续更改查询。
我将在这个例子中使用 3 个变量:
一个。 @columns
:用于生成列 SUM(CASE ..
。
b。 @sql
:用于最终查询。
c。 @maxrows
: 定义“第 xx 行”。
所有变量将设置为:
SET @columns := NULL;
SET @sql := NULL;
SET @maxrows := XX; /*how many first rows*/
设置@columns
和@sql
为NULL
只是一种预防措施,@maxrows
只是你需要旋转的行,在你现在的情况下应该是SET @maxrows := 20;
- 正在设置
@columns
个变量。
WITH RECURSIVE cte AS (
SELECT 1 seq UNION ALL
SELECT seq+1 FROM cte WHERE seq+1 <= @maxrows)
SELECT GROUP_CONCAT(cols SEPARATOR ', \r\n')
INTO @columns
FROM (
SELECT CONCAT('SUM(CASE WHEN rn =',seq,' THEN vals ELSE 0 END) AS "day_',seq,'"')
AS cols
FROM cte UNION
SELECT CONCAT('SUM(CASE WHEN rn >',seq,' THEN vals ELSE 0 END) AS "day_others"')
FROM cte WHERE seq=@maxrows) c;
这里有两个组成部分,第一个是使用通用 table 表达式生成基于 @maxrows
的行序列,然后第二个是连接 SUM(CASE ..
你的 SELECT
查询。 WHEN rn > 20
的最后一个条件单独生成,并使用 UNION
与前 20 个 SUM(CASE ..
组合。最后,GEOUP_CONCAT()
是使生成的语法成为一行所必需的,以便它可以分配给 @columns
变量。注意:设置变量只有在单行时才有效。否则,您将收到 Subquery returns more than 1 row
错误。
运行 此查询随后检查 @columns
变量:SELECT @columns;
- 正在设置
@sql
变量:
SELECT CONCAT('SELECT id,',@columns,'
FROM
(SELECT SUM(value) AS vals, id, DATE_FORMAT(date,"%Y-%m-%d") AS dt,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY date DESC) AS rn
FROM test_table
GROUP BY id, date) v
GROUP BY id;') INTO @sql;
这基本上只是将您已有的子查询与 @columns
变量连接起来,并将其分配给 @sql
变量。检查变量:SELECT @sql;
- 最后一部分只是准备基于
@sql
的语句,执行然后释放它:
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Demo fiddle with separated components and checkings..
P/S:您应该能够复制此查询并直接 运行 它但是如果出现错误(除了可能的 table 或列名),那么它可能是由 group_concat_max_len
设置引起。如果是这样,您可以通过 运行ning:
检查设置
SHOW VARIABLES like 'group_concat_max_len';
如果它显示 1024
(以字节为单位),这意味着 it's the default setting 并且我们在这里使用 GROUP_CONCAT()
进行的操作,它不会成功。因此,您可能想要永久增加该值,或者您可以在完整查询之前添加此语法:
SET SESSION group_concat_max_len = 1000000;
如何通过DATE_FORMAT(date,'%Y-%m-%d')
对值求和并识别前20行数据(按数据desc排序),如果大于20则对剩余值求和,否则为0?假设我的数据低于 SQL,怎么办?非常感谢您的任何建议。
SELECT SUM(value), id, DATE_FORMAT(date,'%Y-%m-%d')
FROM test_table
GROUP BY id, DATE_FORMAT(date,'%Y-%m-%d')
sum(value) id DATE_FORMAT(date,'%Y-%m-%d')
--------------------------------------------
64.98 123456 2021-01-01
64.98 123456 2021-01-02
64.98 123456 2021-01-03
64.98 123456 2021-01-04
64.98 123456 2021-01-05
64.98 123456 2021-01-06
72.34 123456 2021-01-07
64.98 123456 2021-01-08
64.98 123456 2021-01-09
103.80 123456 2021-01-10
64.98 123456 2021-01-11
64.98 123456 2021-01-12
64.98 123456 2021-01-13
64.98 123456 2021-01-14
64.98 123456 2021-01-15
64.98 123456 2021-01-16
64.98 123456 2021-01-17
64.98 123456 2021-01-18
64.98 123456 2021-01-19
64.98 123456 2021-01-20
64.98 123456 2021-01-21
64.98 123456 2021-01-22
64.98 123456 2021-01-23
64.98 123456 2021-01-24
144.98 123456 2021-01-25
64.98 123456 2021-01-26
64.98 123456 2021-01-27
64.98 123456 2021-01-28
64.98 123456 2021-01-29
64.98 123456 2021-01-30
64.98 123456 2021-01-31
64.98 123456 2021-02-01
64.98 123456 2021-02-02
64.98 123456 2021-02-03
64.98 123456 2021-02-04
720.92 123456 2021-02-05
66.98 123456 2021-02-06
66.98 123456 2021-02-07
66.98 123456 2021-02-08
64.98 123456 2021-02-09
64.98 123456 2021-02-10
64.98 223456 2021-01-20
54.98 223456 2021-01-21
......................................
我需要如下输出:
id day_1 day_2 ..... day_20 day_other
--------------------------------------------
123456 64.98 64.98 ..... 234.67 2342.12
223456 64.98 64.98 ..... 234.67 2342.12
终于通过下面SQL解决了这个问题,非常感谢FanoFN的
SELECT id,
SUM(CASE WHEN rn = 1 THEN vals ELSE 0 END) AS 'day_1',
SUM(CASE WHEN rn = 2 THEN vals ELSE 0 END) AS 'day_2',
SUM(CASE WHEN rn = 3 THEN vals ELSE 0 END) AS 'day_3',
SUM(CASE WHEN rn = 4 THEN vals ELSE 0 END) AS 'day_4',
SUM(CASE WHEN rn = 5 THEN vals ELSE 0 END) AS 'day_5',
SUM(CASE WHEN rn = 6 THEN vals ELSE 0 END) AS 'day_6',
SUM(CASE WHEN rn = 7 THEN vals ELSE 0 END) AS 'day_7',
SUM(CASE WHEN rn = 8 THEN vals ELSE 0 END) AS 'day_8',
SUM(CASE WHEN rn = 9 THEN vals ELSE 0 END) AS 'day_9',
SUM(CASE WHEN rn = 10 THEN vals ELSE 0 END) AS 'day_10',
SUM(CASE WHEN rn = 11 THEN vals ELSE 0 END) AS 'day_11',
SUM(CASE WHEN rn = 12 THEN vals ELSE 0 END) AS 'day_12',
SUM(CASE WHEN rn = 13 THEN vals ELSE 0 END) AS 'day_13',
SUM(CASE WHEN rn = 14 THEN vals ELSE 0 END) AS 'day_14',
SUM(CASE WHEN rn = 15 THEN vals ELSE 0 END) AS 'day_15',
SUM(CASE WHEN rn = 16 THEN vals ELSE 0 END) AS 'day_16',
SUM(CASE WHEN rn = 17 THEN vals ELSE 0 END) AS 'day_17',
SUM(CASE WHEN rn = 18 THEN vals ELSE 0 END) AS 'day_18',
SUM(CASE WHEN rn = 19 THEN vals ELSE 0 END) AS 'day_19',
SUM(CASE WHEN rn = 20 THEN vals ELSE 0 END) AS 'day_20',
SUM(CASE WHEN rn > 20 THEN vals ELSE 0 END) AS 'day_others'
FROM
(SELECT SUM(value) AS vals, id, DATE_FORMAT(date,'%Y-%m-%d') AS dt,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY dt DESC) AS rn
FROM test_table
GROUP BY id, dt) v
GROUP BY id;
注意: 不幸的是,此解决方案中的部分组件不适用于旧的 MySQL 版本;正如 OP 提到的
我明白了,那样的话你可以稍微升级一下查询。让我们考虑一下,条件可能会以某种方式更改为前 30 行数据,那么您可能希望使用准备好的语句,这样您就不需要继续更改查询。
我将在这个例子中使用 3 个变量:
一个。@columns
:用于生成列SUM(CASE ..
。
b。@sql
:用于最终查询。
c。@maxrows
: 定义“第 xx 行”。所有变量将设置为:
SET @columns := NULL;
SET @sql := NULL;
SET @maxrows := XX; /*how many first rows*/
设置@columns
和@sql
为NULL
只是一种预防措施,@maxrows
只是你需要旋转的行,在你现在的情况下应该是SET @maxrows := 20;
- 正在设置
@columns
个变量。
WITH RECURSIVE cte AS (
SELECT 1 seq UNION ALL
SELECT seq+1 FROM cte WHERE seq+1 <= @maxrows)
SELECT GROUP_CONCAT(cols SEPARATOR ', \r\n')
INTO @columns
FROM (
SELECT CONCAT('SUM(CASE WHEN rn =',seq,' THEN vals ELSE 0 END) AS "day_',seq,'"')
AS cols
FROM cte UNION
SELECT CONCAT('SUM(CASE WHEN rn >',seq,' THEN vals ELSE 0 END) AS "day_others"')
FROM cte WHERE seq=@maxrows) c;
这里有两个组成部分,第一个是使用通用 table 表达式生成基于 @maxrows
的行序列,然后第二个是连接 SUM(CASE ..
你的 SELECT
查询。 WHEN rn > 20
的最后一个条件单独生成,并使用 UNION
与前 20 个 SUM(CASE ..
组合。最后,GEOUP_CONCAT()
是使生成的语法成为一行所必需的,以便它可以分配给 @columns
变量。注意:设置变量只有在单行时才有效。否则,您将收到 Subquery returns more than 1 row
错误。
运行 此查询随后检查 @columns
变量:SELECT @columns;
- 正在设置
@sql
变量:
SELECT CONCAT('SELECT id,',@columns,'
FROM
(SELECT SUM(value) AS vals, id, DATE_FORMAT(date,"%Y-%m-%d") AS dt,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY date DESC) AS rn
FROM test_table
GROUP BY id, date) v
GROUP BY id;') INTO @sql;
这基本上只是将您已有的子查询与 @columns
变量连接起来,并将其分配给 @sql
变量。检查变量:SELECT @sql;
- 最后一部分只是准备基于
@sql
的语句,执行然后释放它:
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Demo fiddle with separated components and checkings..
P/S:您应该能够复制此查询并直接 运行 它但是如果出现错误(除了可能的 table 或列名),那么它可能是由 group_concat_max_len
设置引起。如果是这样,您可以通过 运行ning:
SHOW VARIABLES like 'group_concat_max_len';
如果它显示 1024
(以字节为单位),这意味着 it's the default setting 并且我们在这里使用 GROUP_CONCAT()
进行的操作,它不会成功。因此,您可能想要永久增加该值,或者您可以在完整查询之前添加此语法:
SET SESSION group_concat_max_len = 1000000;