2

我有以下表結構:SQL連接到相關子查詢,其中表由重疊的範圍相關

項目

ID | Name 
-------- 
1 | Apple 
2 | Pear 
3 | Banana 
4 | Plum 
5 | Tomato 

事件

ItemStart | ItemEnd | EventType | EventDate 
-------------------------------------------- 
    1 | 2 | Planted | 2014-01-01 
    1 | 3 | Picked | 2014-01-02 
    3 | 5 | Eaten | 2014-01-05 

兩個表是僅由Item的主鍵和ItemStart和ItemEnd的範圍(包含)在事件。事件始終引用連續的項目序列,但並非給定項目的所有事件都具有相同的範圍。對於給定的項目,事件不會在同一天發生。

我想生成查詢如下:

List all the Items, and for each Item show the most recent Event

輸出示例:

ID | Name | Event | Date 
---------------------------- 
1 | Apple | Picked | 2014-01-02 (Planted then Picked) 
2 | Pear | Picked | 2014-01-02 (Planted then Picked) 
3 | Banana | Eaten | 2014-01-05 (Picked then Eaten) 
4 | Plum | Eaten | 2014-01-05 (Eaten) 
5 | Tomato | Eaten | 2014-01-05 (Eaten) 

這似乎是合理夠用就面對它,如果有傳統外鍵關係到位(想象一下ItemID而不是ItemStartItemEnd)我可能會加入相關的子查詢,如下所示:

SELECT Name, EventType, EventDate 
FROM Item i 
    INNER JOIN (
     SELECT ItemID, EventType, EventDate 
     FROM Event e 
     WHERE EventDate = (SELECT MAX(EventDate) FROM Event e_max WHERE e_max.ItemID = e.ItemID) 
    ) latest_events ON i.ID = latest_events.ItemID 

然而,在地方我卡的範圍關係,我想要做的事更喜歡這一點,但它不工作:

SELECT Name, EventType, EventDate 
FROM Item i 
    INNER JOIN (
     SELECT ItemStart, ItemEnd, EventType, EventDate 
     FROM Event e 
     WHERE EventDate = (SELECT MAX(EventDate) FROM Event e_max WHERE i.ID >= e_max.ItemStart AND i.ID <= e_max.ItemEnd) 
    ) latest_events ON i.ID >= latest_events.ItemStart AND i.ID <= latest_events.ItemEnd 

我在第6行得到一個錯誤約i.ID >= e_max.ItemStart AND i.ID <= e_max.ItemEnd ,因爲您不能在連接的另一部分中引用i。我想這樣做(在更簡單的例子中這不是必需的),因爲當我構建子查詢時,我不再有一個單一的ID鏈接到 - 重疊範圍意味着有很多可能的方法來包含單個項目,因此我想直接引用該項目,該項目的ID僅在頂級項目表中可用。

我希望這是有道理的。

我正在使用SQL Server 2008 R2。這是爲了一個將在一夜之間運行的報告,所以速度並不像它那麼重要,但是有很多項目(100萬)。雖然每個項目有多個事件,但使用大範圍意味着事件記錄的數量要少得多。

事情我已經想過:

  • 不知怎的,擴大了項目/事件的關係,這樣的事件記錄對所有單個項目。這會導致正在考慮的數據量顯着增加,但會允許使用更簡單的查詢方法。
  • 以某種方式處理事件以約束或合併範圍 - 如果我知道對於給定的項目,其所有事件都具有相同的開始和結束,我可能可能會簡化一些事情。沒有完全想到通過。

如何生成此查詢?提前致謝!

+0

如果我明白我不是舒爾,因爲我不能按照你的預期示例輸出。也許你可以更traditionaly使用視圖加入吧'CREATE VIEW V_EVENT作爲 選擇ItemStart的項目,事件類型,EVENTDATE UNION 選擇ItemEnd,事件類型,EVENTDATE ' – bummi 2014-09-10 20:58:50

+0

[SQL的可能重複 - 通過識別表查找最大日期組](http://stackoverflow.com/questions/25529320/sql-finding-the-maximum-date-group-by-id-table) – Bulat 2014-09-10 21:25:56

回答

3

您可以使用CTErow_number()來做到這一點。

SQL Fiddle Demo

;with cte as 
(
    SELECT *, 
     ROW_NUMBER() OVER (PARTITION BY i.id ORDER BY e.EventDate DESC) as rNum 
    FROM Item i 
    JOIN Event e 
     ON i.id between e.ItemStart and e.ItemEnd 
) 

SELECT ID, 
    Name, 
    EventType, 
    EventDate FROM cte 
WHERE rNum = 1 

基本上CTE已經加入項目和事件,並增加了新的列ROWNUMBER和item.ID.被劃分以下是它的外觀截圖。從這裏我只選擇rNum = 1這應該是每個item.id的最大事件日期。

enter image description here

1

這應該是類似於其他偉大的,在組和加入-上的解決方案:

SELECT * FROM 
    Item i INNER JOIN 
    Event e ON i.id BETWEEN e.ItemStart AND e.ItemEnd 
WHERE NOT EXISTS (-- exclude non-last events 
    SELECT * FROM Event 
    WHERE 
     i.id between ItemStart and ItemEnd 
     AND e.EventDate < EventDate) 
+0

剛剛在@JChao的SQLFiddle中試過了,它並沒有給出正確的結果(不返回所有項目)。我不確定我是否明白它是否足夠解決問題,你能看到什麼嗎? – frumious 2014-09-10 21:16:39

+0

我已經更新了它,適合我 – Bulat 2014-09-10 21:17:10

+0

http://sqlfiddle.com/#!3/de664/8 – Bulat 2014-09-10 21:17:52