2012-09-24 79 views
5

我有一個表,類似於這樣一些數據:迭代查詢,而無需使用CTE

 
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 

我需要編寫標識的價格爲沒有改變 查詢自2012年8月30日起,物品C的價格自9/01/2012以來沒有變化,並且 返回兩者(我們正在尋找物品 與非移動價格)的天數。我不能使用CTE或遊標,或者由於這個sql需要運行的網絡報告 的限制而單獨創建臨時表(select into等)。我只能使用'basic'單遍選擇查詢 (子查詢將盡管)。有沒有人有任何狡猾的想法如何 實現這?

我第一次嘗試是按項目和價格,在價格相同 最新價格,having count > 2,確定最小日期和做分鐘日期和GETDATE之間的DATEDIFF 。然而,這只是標識了第一個 價格的實例,它並沒有考慮到任何後續行可能有不同的價格。希望這是有道理的。

+0

您正在使用哪些DBMS? PostgreSQL的?甲骨文? DB2? –

+1

Btw:你總是可以編寫一個視圖來返回所需的信息,然後在你的報告工具中從該視圖中執行SELECT –

+0

對不起,應該說,這是SQL Server 2008.可悲的是,我無法寫視圖 - 這是供應商託管的數據庫,我們擁有它的只讀權限! – Luke

回答

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

工程,但包括'B'行(OP被排除,因爲他們昨天改變了)。 –

+0

好的通話,我還沒有看到所有的評論。應該很容易過濾掉這些記錄,但我無法在評論中理解它們的確切定義。 –

+0

Tim看起來很有希望,非常感謝!我需要一段時間來玩它來適應實際的數據 - 會讓你知道它是怎麼回事。再次,非常感謝。 – Luke

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] 
+0

謝謝傑森!現在也玩這個。非常感謝幫助。 – Luke

2

我有一個喜歡使用窗口功能,他們是最合適的。而且,在這種情況下,找到相同事物的序列有一個有趣的技巧。枚舉它們(使用row_number)覆蓋所有數據,按項目進行分區並按日期排序。然後列舉它們,包括所有數據,按項目和價格劃分,並按日期排序。

一個,你會得到

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) 

還發現每個項目的最大日期,然後選擇具有最大日期分組。

+0

謝謝戈登。這是一個有趣的選擇 - 也將與此同時發揮。今天學習了很多:-) – Luke