窗口循环功能

时间:2018-05-13 19:35:16

标签: sql sql-server

美好的一天,

我在SSMS中使用MS T-SQL。我试图确定一种基于变量或case语句的窗口函数的方法。我需要窗口继续循环,直到某个结果发生,然后通过这些观察切割窗口。另外,也许有更好的方法在Windows之外做这个,我已经研究了WHILE表达式作为潜在的选项。

以下是一个示例数据集:

   CREATE TABLE #Items ([Transaction] int, [Item] varchar(10), [Price] money, [Price2] varchar(25), [SaleDate] smalldatetime)

   INSERT INTO   #Items ([Transaction], [Item], [Price], [Price2], [SaleDate])
   VALUES (123,'Blue',1100,'Blue1100','04/10/2018'),
   (124,'Blue',1100,'Blue1100','04/09/2018'),
   (125,'Blue',1100,'Blue1100','04/09/2018'),
   (126,'Blue',3000,'Blue3000','03/27/2018'),
   (127,'Blue',1100,'Blue1100','03/27/2018'),
   (128,'Blue',1100,'Blue1100','03/27/2018'),
   (129,'Blue',1100,'Blue1100','03/27/2018'),
   (130,'Blue',1100,'Blue1100','03/27/2018'),
   (131,'Red',3328,'Red3328','04/12/2018'),
   (132,'Red',3328,'Red3328','04/09/2018'),
   (133,'Red',3328,'Red3328','04/06/2018'),
   (134,'Red',3328,'Red3328','04/04/2018'),
   (135,'Red',3328,'Red3328','04/02/2018'),
   (136,'Red',3328,'Red3328','04/02/2018'),
   (137,'Yellow',1340,'Yellow1340','04/09/2018'),
   (138,'Yellow',1340,'Yellow1340','04/08/2018'),
   (139,'Yellow',1340,'Yellow1340','04/08/2018'),
   (140,'Yellow',1500,'Yellow1500','04/05/2018'),
   (141,'Yellow',1340,'Yellow1340','04/05/2018'),
   (142,'Yellow',1340,'Yellow1340','04/05/2018'),
   (143,'Yellow',1340,'Yellow1340','04/02/2018'),
   (144,'Yellow',1340,'Yellow1340','03/31/2018')

在这种情况下,我希望窗口查看按[SaleDate] desc排序的每个[Item],并按顺序创建具有相同[Price]的顺序的窗口大小。只要[价格]没有中断,窗口就会基于这些观察。一旦确定了,我想添加一个列,在窗口中为这些观察结果提供最小的[SaleDate]。

所需结果位于此表的最后一栏 enter image description here

我正在尝试使用以下查询,但无法弄清楚如何让窗口循环:

SELECT 
Transaction
, Item
, Price
,Price2
, SaleDate
,(CASE WHEN PRICE2 = LEAD(PRICE2) OVER (ORDER BY Price ASC, SaleDate DESC ) 
AND LEAD(PRICE2) OVER (ORDER BY Price ASC, SaleDate DESC ) = LEAD(PRICE2) OVER (ORDER BY Price ASC, SaleDate DESC ) 
THEN MIN(SaleDate) ELSE NULL END) 'StartDate'

FROM #Items

GROUP BY 
Transaction
, Item
, Price
,Price2
, SaleDate

欢迎任何和所有建议!谢谢!

2 个答案:

答案 0 :(得分:2)

这可以通过递归CTE完成。

示例SQL:

;with CTE as (
    SELECT [Transaction], Item, Price, Price2, SaleDate, 
    row_number() over (partition by Item order by SaleDate asc, [Transaction] desc) as rn
    FROM #Items
)
, RCTE as (
     SELECT 
       c.*, 
       SaleDate as SaleDatePriceChange
     from CTE c
     where rn = 1

     union all

     SELECT 
       c.*,
       case when c.Price = r.Price then r.SaleDatePriceChange else c.SaleDate end
     from RCTE r 
     join CTE c on c.Item = r.Item and c.rn = r.rn + 1   

)
select [Transaction], Item, Price, Price2, SaleDate, SaleDatePriceChange
from RCTE
order by Item, rn desc;

第一个CTE用于添加row_number。

这样可以更轻松地加入递归CTE中的下一条记录。

答案 1 :(得分:0)

这是获取这些开始日期的另一种方法 这次没有递归。

它使用LAG获取前一记录的价格 这样以前的价格就可以与记录的价格进行比较 如果价格发生变化,IIF将返回1,否则返回0。

SUM窗口函数将向上添加1和0,从而产生排名 诀窍是,当添加0时,等级数不会增加。

然后FIRST_VALUE用于获取其中排名第一的SaleDate。

select 
  [Transaction], Item, Price, Price2, SaleDate, 
  first_value(t.SaleDate) over (partition by t.Item, q2.PriceChangeRank order by t.SaleDate, t.[Transaction] desc) as PriceChangedDate
from
(
    select TransactionID,
      sum(PriceChanged) over (partition by Item order by SaleDate, TransactionID desc) as PriceChangeRank
    from
    (
        select [Transaction] as TransactionID, Item, SaleDate,
          iif(Price != lag(Price) over (partition by Item order by SaleDate, [Transaction] desc),1,0)  as PriceChanged
        from #Items
    ) q1
) q2
join #Items t on (t.[Transaction] = q2.TransactionID)
order by [Transaction];

不确定此方法是否比使用动态SQL更快。 但它是另一种选择。