2012-10-01 39 views
1

我有一個sql查詢來檢查產品記錄在表PRODUCTS中的重疊。 在大多數情況下,查詢可以正常工作,但下列情況除外。重疊數據

select * from products where 
product_reg_no = 'AL-NAPT' 
and (to_date('14-Aug-2001') BETWEEN to_date('27-Aug-2001') AND to_date('30-Aug-2001') 
or to_date('31-Aug-2001') BETWEEN to_date('27-Aug-2001') AND to_date('30-Aug-2001')) 

如何使此查詢捕獲所有記錄部分或完全重疊?

如果需要,我可以提供帶有樣本記錄的表結構。

由於

更新1

我已經加入表的結構和記錄here或如下:

create table products 
(product_reg_no varchar2(32), 
start_date date, 
end_date date); 


Insert into products 
    (product_reg_no, START_DATE, END_DATE) 
Values 
    ('AL-NAPT', TO_DATE('08/14/2012', 'MM/DD/YYYY'), TO_DATE('08/31/2012', 'MM/DD/YYYY')); 
Insert into products 
    (product_reg_no, START_DATE, END_DATE) 
Values 
    ('AL-NAPT', TO_DATE('08/27/2012', 'MM/DD/YYYY'), TO_DATE('08/30/2012', 'MM/DD/YYYY')); 
COMMIT; 

第一個記錄是從八月,14 2012八月, 31 2012與 重疊第二條記錄從2012年8月27日2012年8月30日。那麼,如何修改我的查詢以獲得重疊?

+0

是日期值中的一個(或幾個)應該來自於數據庫中的列?最好爲產品表提供一個最小模式,併爲其提供一些示例行。我打算建議OVERLAP操作符,但Google建議它不提供Oracle記錄(儘管它存在),所以也許你不能(不應該)使用它。你可能想看看[確定兩個日期範圍是否重疊](http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap/328558#328558)。 –

+0

@JonathanLeffler用[sqlfiddle](http://sqlfiddle.com/#!4/03d61/1)更新了我的問題謝謝 – user75ponic

回答

2

請參閱Determine whether two date ranges overlap

您需要評估以下,或者用它來代替<=<上一個小的變體,或許:

Start1 < End2 AND Start2 < End1 

既然你有一個表的工作,你需要有一個自聯接:

SELECT p1.*, p2.* 
    FROM products p1 
    JOIN products p2 
    ON p1.product_reg_no != p2.product_reg_no 
    AND p1.start < p2.end 
    AND p2.start < p1.end; 

的不相等條件確保你沒有得到與自己配對(雖然<條件也保證了創紀錄的,但如果你使用<=,在不相等的條件將是一個好主意。

這將產生兩行用於每個對產品(一行與產品A爲p1和產品B作爲p2,其他與產品B作爲p1和產品A爲p2)。爲防止發生這種情況,請將!=更改爲<>


而且,仔細查看示例數據,可能會發現在註冊編號匹配和日期重疊的行中您非常有趣。在這種情況下,您可以忽略我關於!=<>的詭計,並最終用=代替條件。

SELECT p1.*, p2.* 
    FROM products p1 
    JOIN products p2 
    ON p1.product_reg_no = p2.product_reg_no 
    AND p1.start < p2.end 
    AND p2.start < p1.end; 

SQL小提琴(未保存的)表明,該工程:

SELECT p1.product_reg_no p1_reg, p1.start_date p1_start, p1.end_date p1_end, 
     p2.product_reg_no p2_reg, p2.start_date p2_start, p2.end_date p2_end 
    FROM products p1 
    JOIN products p2 
    ON p1.product_reg_no = p2.product_reg_no 
    AND p1.start_date < p2.end_date 
    AND p2.start_date < p1.end_date 
WHERE (p1.start_date != p2.start_date OR p1.end_date != p2.end_date); 

WHERE子句消除了被連接到自己的行。通過刪除SELECT列表中的重複列名,您可以查看所有數據。我添加了一行:

INSERT INTO products (product_reg_no, start_date, end_date) 
VALUES ('AL-NAPT', TO_DATE('08/27/2011', 'MM/DD/YYYY'), TO_DATE('08/30/2011', 'MM/DD/YYYY')); 

這沒有被選中 - 表明它拒絕了不重疊的條目。

如果你想消除雙行,那麼你必須添加其他花哨的標準:

SELECT p1.product_reg_no p1_reg, p1.start_date p1_start, p1.end_date p1_end, 
     p2.product_reg_no p2_reg, p2.start_date p2_start, p2.end_date p2_end 
    FROM products p1 
    JOIN products p2 
    ON p1.product_reg_no = p2.product_reg_no 
    AND p1.start_date < p2.end_date 
    AND p2.start_date < p1.end_date 
WHERE (p1.start_date != p2.start_date OR p1.end_date != p2.end_date) 
    AND (p1.start_date < p2.start_date OR 
     (p1.start_date = p2.start_date AND p1.end_date < p2.end_date)); 
+0

請參閱我的附錄;對於你的示例數據,用'='替換'!='。 –

+0

當我使用真實數據進行測試時,您的查詢完美無缺。我有一個問題,但我怎麼修改這個接收參數,以便我可以在函數中使用此查詢來檢查任何重疊的記錄,當用戶在存儲在表中之前在應用程序中輸入日期。感謝和讚賞。 – user75ponic

+1

有多種選擇。在某些方面,最簡單的方法是創建第二個表(可能是臨時表),將其稱爲'prospective_registration',與「產品」相同的三列。將新值插入該表中。更改查詢,使'JOIN產品p2'成爲'JOIN prospective_registration p2',並保持其他所有內容不變。否則,您需要用相應的參數替換每個出現的'p2.product_reg_no','p2.start_date'和'p2.end_date',並刪除'JOIN products p2'行。可能還有其他一些簡化可用。 –

2

這是一個奇怪的查詢。您檢查2001年8月14日是2001年8月27日至2001年8月30日之間是否始終是虛假的,或2001年8月31日是2001年8月27日至2001年8月30日期間是否也是虛假的。所以你的where條款將永遠是錯誤的。

編輯:感謝澄清

SQL Fiddle Demo

select p1.product_reg_no 
     , p1.start_date p1s 
     , p1.end_date p1e 
     , p2.start_date p2s 
     , p2.end_date p2e 
from products p1, products p2 
where p1.product_reg_no = p2.product_reg_no 
    and not ( p1.end_date < p2.start_date 
      and p1.start_date > p2.end_date ); 

你想要的是以下情況中(1個代表第一行2第二)

1 1 
2 2 

1 1 
2 2 

1 1 
2 2 

1 1 
2 2 

1 1 
2 2 

那你也可以轉過身來說你不想要這個:

1 1 
    2 2 

    1 1 
2 2 

我以爲你也需要這麼做

1 1 
    2 2 

    1 1 
2 2 

WHERE子句也可以不同書面

not ( p1.end_date < p2.start_date and p1.start_date > p2.end_date ) 

相同

 p1.end_date >= p2.start_date or p1.start_date <= p2.end_date 

我認爲這是所謂的德摩根的法律,當我在學校以前那樣。

您必須考慮如果您的行數超過2行會發生什麼情況。

+0

用[sqlfiddle]更新了我的問題(http://sqlfiddle.com/#!4/03d61/1)謝謝 – user75ponic