如何不将 where 子句应用于窗口函数
Posted
技术标签:
【中文标题】如何不将 where 子句应用于窗口函数【英文标题】:How to not apply a where clause to a window function 【发布时间】:2021-09-05 10:57:03 【问题描述】:我有一个表格显示客户的购买情况,如下所示:
day,transaction_id,customer_id,price
2020-01-01,1,100,10
2020-01-02,2,200,20
2020-01-03,3,100,30
2020-01-04,4,200,40
2020-02-01,5,100,50
2020-02-02,6,200,60
2020-02-03,7,100,70
2020-02-04,8,200,80
我想要一个查询,显示每个用户迄今为止所有交易的总和,但仅限于 2020 年 2 月的交易。
如果我执行以下操作,那么我相信只有 2 月份的交易会在窗口函数中进行评估:
SELECT
transaction_id,
SUM(price) OVER (PARTITION BY customer_id ORDER BY day) AS total
FROM
sales
WHERE
day BETWEEN DATE '2021-02-01' AND DATE '2021-02-28'
如何仅计算二月份的行的窗口函数,但在窗口函数计算中包含所有先前的行?
这只是示例数据,但在实际数据中,有大量的销售额,因此对于指定时间范围之外的所有行,都有大量的窗口函数的冗余计算。
编辑:
我认为我的问题被误解了,因为到目前为止这两个答案都与我想要的相反。
我只想返回 2 月的行程,但窗口函数应该计算 1 月和 2 月的ALL次行程。
结果应该是这样的:
transaction_id,total
5,90
6,120
7,160
8,200
【问题讨论】:
【参考方案1】:我想要一个查询,显示每个用户迄今为止所有交易的总和,但仅限于 2020 年 2 月的交易。
如果我理解正确,您只想显示 2 月份的交易,但您希望总和为所有交易。如果是这样,则使用子查询:
select s.*
from (select s.*,
sum(price) over (partition by customer_id order by day) as running_price
from sales s
) s
where day >= date '2021-02-01' and date < date '2021-03-01';
注意使用月份中的第一个和不等式进行日期比较。这适用于 2020 年(闰年)和 2021 年(非闰年)——具有讽刺意味的是,您的问题中都提到了这两年。
【讨论】:
谢谢。我编辑了我的问题以进行澄清,但是是的,您的理解是正确的。 SQL 引擎会首先为表中的所有行计算窗口函数,然后应用 where 子句,还是会足够智能地知道外部查询只希望为 2 月份的行计算窗口函数? @KOB。 . .我很确定它会计算所有行的值。 有趣,这确实是我问题的重点。在我的实际用例中,我在查询中有几个计算量很大的窗口函数,而且我的表很大。当我只想返回不到 1% 的冗余计算时,这只是执行了大量的冗余计算【参考方案2】:使用条件求和:
SELECT
transaction_id,
SUM(CASE WHEN day BETWEEN DATE '2021-02-01' AND DATE '2021-02-28'
THEN price ELSE 0 END) OVER (PARTITION BY customer_id ORDER BY day) AS total
FROM sales
【讨论】:
【参考方案3】:我想我明白了你的问题。我使用 T-SQL 并创建了临时表和子查询
declare @from as date ='2020-02-01'
declare @to as date='2020-02-28'
select * from sales
select price,
(SELECT SUM(b.price)
FROM sales b
WHERE b.customer_id = a.customer_id and b.transaction_id <= a.transaction_id) as runningTotal,
transaction_id,
customer_id,
day
INTO #Temp from sales a
select * from #Temp where [day] between @from and @to order by customer_id, transaction_id
drop table #temp
enter image description here
【讨论】:
以上是关于如何不将 where 子句应用于窗口函数的主要内容,如果未能解决你的问题,请参考以下文章
在spark sql中对窗口函数使用having子句的语义是什么?