2008-12-18 63 views
4

如何在具有稀疏日期數的表格和具有詳盡數量日期的另一個表格之間進行聯接,以便稀疏日期之間的差距取前一個稀疏日期的值?需要SQL中複雜聯接語句的幫助

說明性的例子:

PRICE table (sparse dates): 
date  itemid price 
2008-12-04 1  $1 
2008-12-11 1  $3 
2008-12-15 1  $7 


VOLUME table (exhaustive dates): 
date   itemid volume_amt 
2008-12-04 1  12345 
2008-12-05 1  23456 
2008-12-08 1  34567 
2008-12-09 1  ... 
2008-12-10 1 
2008-12-11 1 
2008-12-12 1 
2008-12-15 1 
2008-12-16 1 
2008-12-17 1 
2008-12-18 1 

期望的結果:

date  price volume_amt 
2008-12-04 $1  12345 
2008-12-05 $1  23456 
2008-12-08 $1  34567 
2008-12-09 $1  ... 
2008-12-10 $1 
2008-12-11 $3 
2008-12-12 $3 
2008-12-15 $7 
2008-12-16 $7 
2008-12-17 $7 
2008-12-18 $7 

更新:

一對夫婦的人建議相關子查詢是實現期望的結果。 (相關子查詢=包含對外部查詢引用的子查詢。)

這將工作;然而,我應該注意到我使用的平臺是MySQL,相關子查詢的優化程度很差。任何不使用相關子查詢的方法?

+0

你可以編輯標題或刪除並重新開始? – 2008-12-18 17:23:03

+0

看起來像別人做的。是的,沒有在那裏注意。 – 2008-12-18 17:26:50

+0

需要輸入的列名和所需的輸出。現在這個問題的措辭是不明確的 – 2008-12-18 17:26:51

回答

7

這並不像一個LEFT OUTER JOIN到疏表那麼簡單,因爲你想通過外留下的NULL加入到充滿最近的價格。

EXPLAIN SELECT v.`date`, v.volume_amt, p1.item_id, p1.price 
FROM Volume v JOIN Price p1 
    ON (v.`date` >= p1.`date` AND v.item_id = p1.item_id) 
LEFT OUTER JOIN Price p2 
    ON (v.`date` >= p2.`date` AND v.item_id = p2.item_id 
    AND p1.`date` < p2.`date`) 
WHERE p2.item_id IS NULL; 

此查詢將Volume匹配到Price中較早的所有行,然後使用另一個連接來確保我們只找到最近的價格。

我在MySQL 5.0.51上測試了這個。它既不使用相關的子查詢也不使用group by。

編輯:已更新查詢以匹配item_id以及日期。這似乎也起作用。我在(date)上創建了一個索引,在(date, item_id)上創建了一個索引,並且EXPLAIN計劃是相同的。在這種情況下,(item_id, date)上的索引可能會更好。這裏的解釋輸出爲:

+----+-------------+-------+------+---------------+---------+---------+-----------------+------+--------------------------------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref    | rows | Extra        | 
+----+-------------+-------+------+---------------+---------+---------+-----------------+------+--------------------------------------+ 
| 1 | SIMPLE  | p1 | ALL | item_id  | NULL | NULL | NULL   | 6 |          | 
| 1 | SIMPLE  | v  | ref | item_id  | item_id | 22  | test.p1.item_id | 3 | Using where       | 
| 1 | SIMPLE  | p2 | ref | item_id  | item_id | 22  | test.v.item_id | 1 | Using where; Using index; Not exists | 
+----+-------------+-------+------+---------------+---------+---------+-----------------+------+--------------------------------------+ 

但我有一個非常小的數據集,並且優化可能取決於較大的數據集。您應該嘗試使用更大的數據集來分析優化。

編輯:我之前粘貼了錯誤的EXPLAIN輸出。上面的一個已更正,並更好地使用(item_id, date)索引。

2
SELECT v.date, p.price, v.volume 
FROM volume v 
LEFT JOIN Price p ON p.itemID=v.itemID 
    AND p.[date] = (
        SELECT MAX([date]) 
        FROM price p2 
        WHERE p2.[date] <= v.[date] AND p2.itemid= v.itemid 
        GROUP BY p2.[date] 
        ) 
+0

將無法​​正常工作 - 將僅在有新價格時返回數量。期望的輸出是該卷應當返回當天的價格或者具有新價格的最近的前一天。 – 2008-12-18 17:35:34

0
SELECT Volume.date, volume.itemid, price.price, volume.volume_amt 
FROM Volume 
LEFT OUTER JOIN Price 
ON Volume.date = Price.date 

可能。我的SQL福弱

3

假設有每個日期只有1價格/爲itemid:

select v.date, v.itemid, p.price 
from volume v 
join price p on p.itemid = v.item_id 
where p.date = (select max(p2.date) from price p2 
       where p2.itemid = v.itemid 
       and p2.date <= v.date); 
0

這種方法在甲骨文工作。不知道其他數據庫,你沒有指定。如果這個確切的語法在你的數據庫中不起作用,我猜想有類似的技術。

dev> select * from price; 

AS_OF    ID  AMOUNT 
----------- ---------- ---------- 
04-Dec-2008   1   1 
11-Dec-2008   1   2 
15-Dec-2008   1   3 

dev> select * from volume; 

DAY     ID  VOLUME 
----------- ---------- ---------- 
05-Dec-2008   1   1 
06-Dec-2008   1   2 
07-Dec-2008   1   3 
08-Dec-2008   1   4 
09-Dec-2008   1   5 
10-Dec-2008   1   6 
11-Dec-2008   1   7 
12-Dec-2008   1   8 
13-Dec-2008   1   9 
14-Dec-2008   1   10 
15-Dec-2008   1   11 
16-Dec-2008   1   12 
17-Dec-2008   1   13 
18-Dec-2008   1   14 
19-Dec-2008   1   15 
20-Dec-2008   1   16 
21-Dec-2008   1   17 
22-Dec-2008   1   18 
23-Dec-2008   1   19 

dev> select day, volume, amount from (
    2 select day, volume, (select max(as_of) from price p where p.id = v.id and as_of <= day) price_as_of 
    3  from volume v 
    4 ) 
    5 join price on as_of = price_as_of 
    6 order by day; 

DAY    VOLUME  AMOUNT 
----------- ---------- ---------- 
05-Dec-2008   1   1 
06-Dec-2008   2   1 
07-Dec-2008   3   1 
08-Dec-2008   4   1 
09-Dec-2008   5   1 
10-Dec-2008   6   1 
11-Dec-2008   7   2 
12-Dec-2008   8   2 
13-Dec-2008   9   2 
14-Dec-2008   10   2 
15-Dec-2008   11   3 
16-Dec-2008   12   3 
17-Dec-2008   13   3 
18-Dec-2008   14   3 
19-Dec-2008   15   3 
20-Dec-2008   16   3 
21-Dec-2008   17   3 
22-Dec-2008   18   3 
23-Dec-2008   19   3