应用 SUM(其中 date1 和 date2 之间的日期)
Posted
技术标签:
【中文标题】应用 SUM(其中 date1 和 date2 之间的日期)【英文标题】:Apply SUM( where date between date1 and date2) 【发布时间】:2021-05-27 04:30:51 【问题描述】:我的桌子目前是这样的:
+---------+---------------+------------+------------------+
| Segment | Product | Pre_Date | ON_Prepaid |
+---------+---------------+------------+------------------+
| RB | 01. Auto Loan | 2020-01-01 | 10645976180.0000 |
| RB | 01. Auto Loan | 2020-01-02 | 4489547174.0000 |
| RB | 01. Auto Loan | 2020-01-03 | 1853117000.0000 |
| RB | 01. Auto Loan | 2020-01-04 | 9350258448.0000 |
+---------+---------------+------------+------------------+
我正在尝试对 7 天内的“ON_Prepaid”值求和,比如说从“2020-01-01”到“2020-01-07”。 这是我尝试过的
drop table if exists ##Prepay_summary_cash
select *,
[1W_Prepaid] = sum(ON_Prepaid) over (partition by SEGMENT, PRODUCT order by PRE_DATE rows between 1 following and 7 following),
[2W_Prepaid] = sum(ON_Prepaid) over (partition by SEGMENT, PRODUCT order by PRE_DATE rows between 8 following and 14 following),
[3W_Prepaid] = sum(ON_Prepaid) over (partition by SEGMENT, PRODUCT order by PRE_DATE rows between 15 following and 21 following),
[1M_Prepaid] = sum(ON_Prepaid) over (partition by SEGMENT, PRODUCT order by PRE_DATE rows between 22 following and 30 following),
[1.5M_Prepaid] = sum(ON_Prepaid) over (partition by SEGMENT, PRODUCT order by PRE_DATE rows between 31 following and 45 following),
[2M_Prepaid] = sum(ON_Prepaid) over (partition by SEGMENT, PRODUCT order by PRE_DATE rows between 46 following and 60 following),
[3M_Prepaid] = sum(ON_Prepaid) over (partition by SEGMENT, PRODUCT order by PRE_DATE rows between 61 following and 90 following),
[6M_Prepaid] = sum(ON_Prepaid) over (partition by SEGMENT, PRODUCT order by PRE_DATE rows between 91 following and 181 following)
into ##Prepay_summary_cash
from ##Prepay1
如果日期是连续的,应该没问题;但是,“Pre_Date”中缺少一些日期(您知道银行在周日不工作等)。
所以我正在尝试类似的工作
[1W] = SUM(ON_Prepaid) over (where Pre_date between dateadd(d,1,Pre_date) and dateadd(d,7,Pre_date))
类似的东西。因此,如果本身没有 2020-01-05 的记录,则结果应仅将 2020 年 1 月 1、2、3、4、6、7 的日期相加,而不是 1、2、3、4、6, 7,8(8 因为“第 7 行以下”)。或者例如,我在 30 天之内丢失了记录,那么所有这 30 条记录都应该加起来为 0。所以 45 天应该只返回 15 天的值。 我已经尝试在整个论坛中查找,但答案还不够。你们能帮帮我吗?或者将我链接到问题已经解决的线程。
非常感谢。
【问题讨论】:
您是否尝试过条件总和,例如sum(case when condition then value else 0 end)
?
我做到了,总和(当 pre_date 介于 dateadd(d,1,predate) 和 dateadd(d,7,predate) 然后 ON_Prepaid else 0 end) 只返回 0
如果您正在查看评估值(而不是 行数),您可能希望让窗口函数使用 RANGE 而不是 ROWS,例如 sqlpassion.at/archive/2015/01/22/…
这个条件永远不会满足? 'pre_date' 永远不会在那个范围内
还是像datepart(week)
分区一样简单?
【参考方案1】:
如果日期是连续的,应该没问题
然后让它们连续。将您的真实数据(分组为每天一行)加入您的日历表(制作一个,或使用递归 cte 为您生成来自 X 的 360 个日期的列表),您的查询将成功
WITH d as
(
SELECT *
FROM
(
SELECT *
FROM cal
CROSS JOIN
(SELECT DISTINCT segment s, product p FROM ##Prepay1) x
) c
LEFT JOIN ##Prepay1 p
ON
c.d = p.pre_date AND
c.segment = p.segment AND
c.product = p.product
WHERE
c.d BETWEEN '2020-01-01' AND '2021-01-01' -- date range on c.d not c.pre_date
)
--use d.d/s/p not d.pre_date/segment/product in your query (sometimes the latter are null)
select *,
[1W_Prepaid] = sum(ON_Prepaid) over (partition by s, s order by d.d rows between 1 following and 7 following),
...
CAL 只是一个包含单列日期的表格,每天一个,没有时间,延伸到过去/未来的 n 千天
希望注意月份的天数是可变的,因此 6M 有点用词不当。将月份称为 180D、90D 等可能会更好
还想指出,您的查询将您的数据按行划分为组。如果您想在行日期后最多 180 天执行求和,则需要提取一年的数据,以便在第 180 行(6 月)上,您可以使用 12 月的数据进行求和(从 6 月开始,12 月为 6 个月)
如果您想将查询限制为仅显示到 6 月(但包括从 6 月之后的 6 个月汇总的数据),您需要再次将其全部包装在子查询中。您不能在求和的查询中“在 jan 和 jun 之间的位置”,因为 where 子句在 window 子句之前完成(这样做会在求和之前删除 dec 数据)
其他一些数据库使这更容易,我想到了 Oracle 和 Postgres;他们可以在其他行值与当前行值有一定距离的范围内执行求和。 SQL Server 仅有效地支持基于行的索引而不是其值的距离(基于值的距离支持仅限于“具有相同值的行”,而不是“具有 n 高于或低于当前行”)。我想可以通过交叉应用或选择中的协调子来满足要求,尽管我会小心检查性能..
SELECT *,
(SELECT SUM(tt.a) FROM x tt WHERE t.x = tt.x AND tt.y = t.y AND tt.z BETWEEN DATEADD(d, 1, t.z) AND DATEADD(d, 7, t.z) AS 1W
FROM
x t
【讨论】:
我设法创建了一个“##CAL”表,是的,问题变得简单多了。但是,“SELECT d FROM ##CAL CROSS JOIN (SELECT DISTINCT SEGMENT s, PRODUCT p FROM ##Prepay1) x”只返回了一个表,其中包含 1 列“d”,日期范围从 2020-01-01 到 2021-04 -30(我设置了截止限制)。关于交叉连接如何失败的任何建议? 等等,没关系,我从“select d from ##CAL”更改为“select * from ##CAL”,它起作用了。不知道为什么大声笑 这是我的错字;你的修复是正确的。这纯粹是因为虽然cal CROSS JOIN (SELECT p, s FROM...)
是 3 列(1 来自 cal,2 来自不同的子查询),但仅选择 d
然后丢弃交叉连接的列.. SELECT *
或 SELECT cal.d, x.p, x.s
将允许日期和要通过的产品/细分市场以上是关于应用 SUM(其中 date1 和 date2 之间的日期)的主要内容,如果未能解决你的问题,请参考以下文章
为啥 javascript date1 == date2 不起作用? [复制]
PostgreSQL SELECT date在date1和date2之间