查询以返回连续 X 天内值的最低 SUM
Posted
技术标签:
【中文标题】查询以返回连续 X 天内值的最低 SUM【英文标题】:Query to return the lowest SUM of values over X consecutive days 【发布时间】:2019-02-07 08:19:56 【问题描述】:我什至不知道该怎么说这个!...
我有一个包含两列的表,即价格(双精度)和开始日期(日期)。我需要能够查询表并返回 X 行,对于这个例子来说 3 - 我需要拉回具有连续日期的 3 行,例如2019 年 5 月 7 日、8 日、9 日,这些日期范围内的总价格值最低。
我正在考虑一个需要 startDateRange、endDateRange、持续时间的函数。
它将返回 startDateRange 和 endDateRange 之间的行数(持续时间),而这三行的总和将是该日期范围内连续日期的任意行数中最便宜(最低)的总和。
例如,如果我想要 2019 年 5 月 1 日至 2019 年 5 月 14 日之间最便宜的 3 个日期,则将返回突出显示的 3 行;
我认为 LEAD() 和 LAG() 可能是一个起点,但我并不是真正的 SQL 人,所以不确定是否有更好的解决方法。
我目前在我的业务层上开发了一些 c# 来执行此操作,但在大型数据集上它有点迟钝 - 直接从我的数据层获取记录列表会很好。
任何想法将不胜感激!
提前致谢。
【问题讨论】:
最便宜的如何计算?连续三行的平均值? 我现在正在使用 SQL Server Management Studio 2014 @jarlh。 andomar 已经通过他的查询 @salman-a 几乎破解了我所追求的内容,现在只是想在我的 dbms 中更好地理解查询,将其分解为 3 行 【参考方案1】:您可以使用窗口函数计算 3 天的平均值。然后使用top 1
选择平均值最低的 3 行集合:
select top 1 StartDt
, AvgPrice
from (
select StartDt
, avg(Price) over (order by StartDt rows between 2 preceding
and current row) AvgPrice
, count(*) over (order by StartDt rows between 2 preceding
and current row) RowCnt
from prices
) sets_of_3_days
where RowCnt = 3 -- ignore first two rows
order by
AvgPrice desc
【讨论】:
哦哦!这几乎就是我所追求的,非常感谢 - 我已经将 avg(Price) 换成了 sum(Price) - 这让我获得了 X 天总数的记录。但是有一个障碍,它带来了连续 3 天最便宜的总价格的一行......即 2019 年 5 月 12 日:1531 英镑(总计 480,510,541) - 有没有办法单独拉回三行(我的屏幕截图中的第 10、11、12 行?)再次感谢!从来没有使用过前面的命令或类似的东西! 此解决方案仅在行连续时才考虑日期是否连续。证明?将第 10 天的日期更新到第 9 天并运行此过程【参考方案2】:这是您的解决方案,当您开始声明日期时,逻辑就开始了。一切顺利。
--table example
declare @laVieja table (price float,fecha date )
insert into @laVieja values (632,'20150101')
insert into @laVieja values (649,'20150102')
insert into @laVieja values (632,'20150103')
insert into @laVieja values (607,'20150104')
insert into @laVieja values (598,'20150105')
insert into @laVieja values (624,'20150106')
insert into @laVieja values (641,'20150107')
insert into @laVieja values (598,'20150108')
insert into @laVieja values (556,'20150109')
insert into @laVieja values (480,'20150110')
insert into @laVieja values (510,'20150111')
insert into @laVieja values (541,'20150112')
insert into @laVieja values (634,'20150113')
insert into @laVieja values (634,'20150114')
-- end of setting up table example
--declaring dates
declare @fechaIni date, @fechaEnds date
set @fechaIni = '20150101'
set @fechaEnds = '20150114'
--assigning order based on price
select * , ROW_NUMBER() over (order by price) as unOrden
into #laVieja
from @laVieja
where fecha between @fechaIni and @fechaEnds
-- declaring variables for cycle
declare @iteracion float = 1 ,@iteracionMaxima float, @fechaPrimera date, @fechaSegunda date, @fechaTercera date
select @iteracionMaxima = max(unOrden) from #laVieja
--starting cycle
while(@iteracion <= @iteracionMaxima)
begin
--assigning dates to variables
select @fechaPrimera = fecha from #laVieja where unOrden = @iteracion
select @fechaSegunda = fecha from #laVieja where unOrden = @iteracion + 1
select @fechaTercera = fecha from #laVieja where unOrden = @iteracion + 2
--comparing variables
if(@fechaTercera = DATEADD(day,1,@fechaSegunda) and @fechaSegunda = DATEADD(day,1,@fechaPrimera))
begin
select * from #laVieja
where unOrden in (@iteracion,@iteracion+1,@iteracion+2)
set @iteracion = @iteracionMaxima
end
set @iteracion +=1
end
【讨论】:
嗨,谢谢,是的,我认为我的解释令人困惑!它需要有连续的日子,这会给我最便宜的 3 天,但它们不一定是连续的(例如 11 日、12 日、13 日)。干杯 嗨jezorama,您需要做的就是通过分配开始日期和结束日期来设置代码的限制。鉴于日期是连续的,查询应该返回 3 个最小值。 太好了,谢谢,这正是我所追求的 - 看起来比 @andomar 的解决方案复杂一点 - 我现在就给它一个爆炸。我也可以用我的 SQL 学习一些西班牙语:D 哈哈,这也是代码的副作用 :) 很高兴它能达到目的。 select top 1 StartDt , AvgPrice from ( select StartDt , sum(Price) over (order by StartDt rows between 2 before and current row) AvgPrice , count(1) over (order by StartDt rows between 2前一行和当前行) RowCnt from #laVieja2 ) sets_of_3_days where RowCnt = 3 -- 忽略前两行按 AvgPrice 排序【参考方案3】:您可以使用带有OVER (... ROWS BETWEEN)
子句的窗口函数来计算特定行数的总和/平均值。然后您可以使用ROW_NUMBER
查找其他两行。
WITH cte1 AS (
SELECT *
, SUM(Price) OVER (ORDER BY Date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS wsum
, ROW_NUMBER() OVER (ORDER BY Date) AS rn
FROM #t
), cte2 AS (
SELECT TOP 1 rn
FROM cte1
WHERE rn > 2
ORDER BY wsum, Date
)
SELECT *
FROM cte1
WHERE rn BEtWEEN (SELECT rn FROM cte2) - 2 AND (SELECT rn FROM cte2)
在上述查询中,将 2 替换为 窗口大小 - 1。
【讨论】:
phwoaarrrr。史诗。我正在根据日期和价格执行一些可怕的 IN 子句,以从 SUM 行中获取我想要的 3 行的列表,但显然,我应该远离 SQL,因为这就是你的做法!非常感谢! 有没有办法让这个部分中的数值动态化:“ORDER BY Date ROWS BETWEEN 2 PRECEDING”,即数字“2”?我似乎无法用变量替换那个 2 值。再次感谢。 看起来我必须通过环顾四周来动态构建 SQL:***.com/questions/29695746/… 您可以使用相关子查询,或者交叉应用。但那些表现不佳。 见dbfiddle.uk/…以上是关于查询以返回连续 X 天内值的最低 SUM的主要内容,如果未能解决你的问题,请参考以下文章