2010-01-22 29 views
5

編輯1(說明):謝謝你到目前爲止的答案!迴應令人欣慰。
我想澄清一點問題,因爲根據答案我認爲我沒有正確描述問題的一個方面(而且我確定這是我的錯,因爲即使對我自己也難以定義它)。
這裏的問題:結果集應該只包含tstamp BETWEEN'2010-01-03'和'2010-01-09'的記錄,以及一個記錄,其中第一個order_num的tstamp爲NULL設置(有總是是一個與每個order_num爲空tstamp)。
到目前爲止給出的答案似乎包括所有記錄爲某一order_num如果有任何與tstamp BETWEEN'2010-01-03'和'2010-01-09'。例如,如果另一條記錄的order_num = 2和tstamp = 2010-01-12 00:00:00,則應將而不是包含在結果中。比使用「A UNION(B in A)」更高效的SQL?

原始問題:
考慮包含ID(唯一的),order_num,TSTAMP(時間戳)的訂單表,和ITEM_ID(包含在訂單單項目)。 tstamp爲空,除非訂單已被修改,在這種情況下,存在具有相同order_num和tstamp的另一條記錄,然後包含發生更改時的時間戳。

例...

 
id order_num tstamp    item_id 
__ _________ ___________________ _______ 
0   1       100 
1   2       101 
2   2 2010-01-05 12:34:56  102 
3   3       113 
4   4       124 
5   5       135 
6   5 2010-01-07 01:23:45  136 
7   5 2010-01-07 02:46:00  137 
8   6       100 
9   6 2010-01-13 08:33:55  105 

什麼是最有效的SQL語句一定的日期範圍內檢索所有已修改一次或多次的訂單(基於order_num)的?換句話說,對於每個訂單,我們需要所有具有相同order_num的記錄(包括具有NULL tstamp的記錄),對於每個order_num WHERE至少有一個order_num具有tstamp NOT NULL AND tstamp BETWEEN'2010-01-03' AND'2010-01-09'。這是「我至少有一個order_num有tstamp NOT NULL」,我很難。

結果集應該是這樣的:

 
id order_num tstamp    item_id 
__ _________ ___________________ _______ 
1   2       101 
2   2 2010-01-05 12:34:56  102 
5   5       135 
6   5 2010-01-07 01:23:45  136 
7   5 2010-01-07 02:46:00  137 

,我想出了是這樣的SQL,這基本上是「A UNION(以A-B)」,但它慢慢地執行,我希望有是一種更有效的解決方案:

 
SELECT history_orders.order_id, history_orders.tstamp, history_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09') 
    AS history_orders 
UNION 
SELECT current_orders.order_id, current_orders.tstamp, current_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp IS NULL) 
    AS current_orders 
WHERE current_orders.order_id IN 
    (SELECT orders.order_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09'); 
+0

我很好奇提供的查詢的性能,也許你可以分享測試結果? – 2010-01-22 21:38:53

+0

我會盡快報告最終解決方案的性能改進情況 - 這很重要。 – machinatus 2010-01-25 15:03:21

回答

0

再次感謝您的所有建議。我發現了三種解決方案,包括我的原創。最後,我添加了一些表現結果,這些結果並不像我希望的那麼好。如果有人能改善這一點,我會很高興!

1)迄今爲止發現的最好的解決辦法似乎是:

 
SELECT history_orders.order_id, history_orders.tstamp, history_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09' 
    OR orders.tstamp IS NULL) 
    AS history_orders 
WHERE history_orders.order_id IN 
    (SELECT orders.order_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09'); 

2)我使用EXISTS到位的,這需要一個額外的也試過WHERE子句中的最後一個SELECT:

 
SELECT history_orders.order_id, history_orders.tstamp, history_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09' 
    OR orders.tstamp IS NULL) 
    AS history_orders 
WHERE EXISTS 
    (SELECT orders.order_id 
    FROM orders 
    WHERE history_orders.order_id = orders.order_id 
    AND orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09'); 

3)最後是我的原始解決方案,使用UNION。

評論:
要在表的大小進行評論,我實際的「現實世界」的問題涉及含98,2189,43897,785656條記錄分別爲4個表(帶內連接連接)。

性能 - 我跑了每個解決方案的三倍,這裏是我的真實世界的結果:
1:52,51,51秒
2:54,54,53號
3:56,56,第56號

+0

你在order_id和tstamp上有索引嗎? – 2010-01-25 22:12:13

+0

不,我沒有權力修改設計,因爲這不是關鍵報告。它不會經常運行,所以我對我現在擁有的東西非常滿意。不是說我沒有興趣進一步改進事情,只是爲了我自己的知識! – machinatus 2010-01-27 16:03:20

3

也許一個子查詢:

select * from order o where o.order_num in (select distinct 
    order_num from order where tstamp between '2010-01-03' and '2010-01-09') 
+0

+1是前三種幾乎相同的解決方案中最具可讀性的。 – egrunin 2010-01-22 21:35:48

+0

所以,在我的原始問題中包含根據我的說明(「編輯1」)所需的更改後,我的解決方案是使用此答案,同時將WHERE子句添加到第一個選擇的子查詢中,結果限制爲 tstamp BETWEEN' 2010-01-03'AND'2010-01-09' OR tstamp IS NULL。 我會盡快添加一個完整正確的答案。 – machinatus 2010-01-25 15:02:46

1

,我就必須misund erstood,這樣的事情應該做的伎倆:

SELECT o1.id, o1.order_num, o.tstamp, o.item_id 
FROM orders o1 
WHERE EXISTS(
    SELECT * FROM orders o2 
    WHERE o1.order_num = o2.order_num 
     AND o2.tstamp BETWEEN '2010-01-03' AND '2010-01-09') 

使用EXISTS的好處是,它一旦停止,因爲罰款的第一場比賽。

0

希望我的問題得到了解決。這應該返回訂單上已提交的時間戳內已更改的所有訂單。

SELECT o.order_id, o.tstamp, o.item_id 
FROM orders o 
JOIN (SELECT DISTINCT o2.order_num 
     FROM orders o2 
     WHERE o2.tstamp BETWEEN '2010-01-03' AND '2010-01-09') o3 
ON (o3.order_num = o.order_num) 
0

您可以自行加入表格。簡化後,這看起來像:

select order_id 
from orders all_orders 
inner join orders not_null_orders 
    on all_orders.order_id = not_null_orders.order_id 
where 
    not_null_orders.tstamp is not null 
    and all_orders.tstamp between '2010-01-03' AND '2010-01-09' 
1

我知道現在已經很晚了,但是我剛剛看到這篇文章,我想也許我應該試試這個,這個查詢如何,與上述所有解決方案相比,它非常小,並且解決了這個問題。

select * from orders_gc where order_num in 
    (select order_num 
    from orders_gc 
    group by order_num 
    having count(id) > 1 and 
    MAX(tstamp) between '03-jan-2010' and '09-jan-2010') 
相關問題