应用 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 之间的日期)的主要内容,如果未能解决你的问题,请参考以下文章

在 Redshift 中从表中选择 Date1、Date2

Excel-计算年龄工龄 datedif()

为啥 javascript date1 == date2 不起作用? [复制]

PostgreSQL SELECT date在date1和date2之间

在比较下一条记录的 Date1 和当前记录的 Date2 时查询列出记录

关于datetime 和 int 之间相互转换