不使用CTE(或游标!)的迭代查询

时间:2012-09-24 18:41:50

标签: sql sql-server-2008

我在表格中有一些类似于此的数据:

Item    Date         Price
A       8/29/2012    $3
B       8/29/2012    $23
C       8/29/2012    $10
A       8/30/2012    $4
B       8/30/2012    $25
C       8/30/2012    $11
A       8/31/2012    $3
B       8/31/2012    $22
C       8/31/2012    $8
A       9/01/2012    $3
B       9/01/2012    $26
C       9/01/2012    $9
A       9/02/2012    $3
B       9/02/2012    $24
C       9/02/2012    $9

我需要编写一个查询,确定A的价格没有变化 自2012年8月30日起,自C 9/2012以来,C项的价格没有变化 返回两者的经过天数(我们正在寻找物品 不动的价格)。我不能使用CTE,或游标,或单独创建 由于Web报告的限制,临时表(select into等) 这个sql需要运行的工具。我只能使用'基本'单通道选择查询 (子查询会起作用)。有没有人对如何有任何狡猾的想法 实现这个??

我的第一次尝试是按物品和价格分组,其中价格与价格相同 最新价格having count > 2,确定最短约会和做日期 在min date和getdate之间。然而,这仅仅标识了第一个实例 这个价格,它没有考虑任何可能有的后续行 不同的价格。希望这是有道理的。

3 个答案:

答案 0 :(得分:2)

*已更新with fiddle:*

这会有用吗?

SELECT ct.Item,
    ct.Price,
    datediff(day, max(yt.[Date]), ct.[Date]) AS ChangeDays
FROM
    (SELECT Item, max(Date) as LastDate FROM YourTable GROUP BY Item) maxdata
    INNER JOIN YourTable ct on ct.Item = maxdata.Item and ct.[Date] = maxdata.LastDate
    INNER JOIN YourTable yt on yt.Item = ct.Item and yt.[Date] < ct.[Date] and yt.Price <> ct.Price
GROUP BY ct.Item, ct.Price, ct.[Date]

答案 1 :(得分:2)

我已经给出了两种类型的年龄,并说明了表中只存在一次的项目(它们没有旧日期)。请告诉我们这有多接近。

更新:我必须更正“PriceAgeToNow”中的日期计算,并且我还尝试过滤掉仅有1天新价格的记录。这是SQL Fiddle

-- Get the age of the current price
select *
    , datediff(d, c.OldDate, getdate()) as PriceAgeToNow
    , datediff(d, c.OldDate, c.NewDate) as PriceAgeToNewestDate
from (
    select *
        -- Get max date of former price
        , isnull(
            (select max(Date) from PricingTable where Item = b.Item and Date < b.NewDate and Price != b.NewPrice), b.NewDate
        ) as OldDate
    from (
        -- Get current price
        select *
            , (select Price from PricingTable where Item = a.Item and Date = a.NewDate) as NewPrice
        from (
            -- Get current date
            select Item
                , max(Date) as NewDate
            from PricingTable
            group by Item
        ) a
    ) b
) c
-- Attempt to filter out price changes that have only lasted 1 day
where datediff(d, c.OldDate, c.NewDate) > 1

答案 2 :(得分:2)

我倾向于使用最适合的Windows功能。并且,在这种情况下,有一个有趣的技巧来查找相同的事物序列。在所有数据上枚举它们(带有row_number),按项目分区并按日期排序。然后在所有数据上枚举它们,按项目和价格进行分区,并按日期排序。

对于A,你会得到

A 8/29 $3 1 1
A 8/30 $4 2 1
A 8/31 $3 3 2
A 9/1  $3 4 3
A 9/3  $3 5 4

对于在数据中保持不变的任何价格序列,最后两列之间的差异是不变的。然后我们可以使用它来查找该序列何时开始。以下查询采用此方法:

select item, price, (id_seqnum - ipd_seqnum) as groupid, min(date) as mindate
from (select p.*,
             row_number() over (partition by item order by date) id_seqnum,
             row_number() over (partition by item, price order by date) as ipd_seqnum,
             max(date) over (partition by item) as maxdate
      from prices p
     ) t
group by item, price, (id_seqnum - ipd_seqnum)
having max(date) = max(maxdate)

它还会找到每个项目的最大日期,然后选择具有最大日期的分组。