with a as (select '2023-05-06' as dt, 12 as val union select '2023-05-10',110 union select '2023-05-08',80), b as (select max(dt) max_dt,min(dt) min_dt from a), z as (select DATE(DATE_SUB(CURDATE(),INTERVAL rn day)) as dt from (SELECT ROW_NUMBER() over() as rn FROM (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) a ,(SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) b ,(SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) c ) t ), t as (select z.* from z,b where dt>=b.min_dt and dt <= b.max_dt ) select t.dt,ifnull(a.val,0) as val from t left join a on t.dt = a.dt order by t.dt;
看到上面的SQL 是不是有一种要放弃的感觉。太长了,确实太长了。我们来解析一下 都是干嘛的。我们这里用的是MySQL with 的语法,这个语法的好处就是可以把SQL写的贼长。然后还能年的懂。
先看:
1
with a as (select '2023-05-06' as dt, 12 as val union select '2023-05-10',110 union select '2023-05-08',80)
这一段就是我们造三行数据,实际业务中应该用真实的业务表数据替换。接下来
1
b as (select max(dt) max_dt,min(dt) min_dt from a),
这个就是找到业务里最大的日期,和最小的日期。以方便后面的补全。然后就是特别长的 z
1 2 3 4 5 6 7 8
z as (select DATE(DATE_SUB(CURDATE(),INTERVAL rn day)) as dt from (SELECT ROW_NUMBER() over() as rn FROM (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) a ,(SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) b ,(SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) c ) t ),
create view vn as SELECT ROW_NUMBER() over() as rn FROM (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) a ,(SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) b ,(SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) c
这样一个 1 到 1000 的视图就创建好了。前面的SQL 也可以简化为:
1 2 3 4 5
with a as (select '2023-05-06' as dt, 12 as val union select '2023-05-10',110 union select '2023-05-08',80), b as (select max(dt) max_dt,min(dt) min_dt from a), z as (select DATE(DATE_SUB(CURDATE(),INTERVAL rn day)) as dt from vn), t as (select z.* from z,b where dt>=b.min_dt and dt <= b.max_dt ) select t.dt,ifnull(a.val,0) from t left join a on t.dt = a.dt order by t.dt;
with a as (select '2023-04' as dt, 12 as val union select '2023-06',110 union select '2023-07',80), b as (select max(dt) max_dt,min(dt) min_dt from a), z as (select date_format(DATE_SUB(CURDATE(),INTERVAL rn month),'%Y-%m') as dt from vn), t as (select z.* from z,b where dt>=b.min_dt and dt <= b.max_dt ) select t.dt,ifnull(a.val,0) from t left join a on t.dt = a.dt order by t.dt;