查询以返回连续X天的最低值SUM

时间:2019-02-07 08:19:57

标签: sql sql-server window-functions

我什至不知道该如何措辞!...

我有一个包含两列的表,分别是Price(两倍)和StartDate(日期)。我需要能够查询表并返回X行数,对于本示例来说要说3-我需要拉回具有连续日期的3行,例如2019年5月7日,8日,9日,这是日期范围内总和最低的价格值。

我在考虑一个需要startDateRange,endDateRange,持续时间的函数。

它将返回startDateRange和endDateRange之间的行数(持续时间),总和后的那三行将是该日期范围内连续日期中任何数量的行中最便宜(最低)的总和。

例如,如果我想要从2019年5月1日到2019年5月14日之间最便宜的3个日期,将返回突出显示的3行;

enter image description here

我认为LEAD()和LAG()可能是一个起点,但是我并不是SQL专家,所以不确定是否有更好的方法。

我目前已经在业务层上开发了一些c#来执行此操作,但是在大型数据集上它有点迟钝-可以直接从我的数据层获取记录列表会很不错。

任何想法将不胜感激!

谢谢。

3 个答案:

答案 0 :(得分:3)

您可以使用窗口函数计算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

答案 1 :(得分:1)

您可以将窗口函数与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

答案 2 :(得分:0)

这是您的解决方案,当您开始声明日期时,逻辑即开始。一切顺利。

--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