2016-11-07 39 views
0

我試圖在表中配對左右部分。該表格包含唯一部件ID,標識符和左/右指示器列。我收到了類似question的答案,假設左邊的部分總是出現在右邊,但我發現情況並非如此。Oracle SQL配對右標識符的序列號

當前識別一對的唯一方法是,如果它們具有相同的標識符並且匹配部分是前一部分或後一部分,如果右手部分與左手後續部分具有相同的標識符,則是正確的一對,但如果左手部分與右後一部分具有相同的標識符,那麼這是正確的一對。例如(當前的ID,標識符是VARCHAR2)

(ID 4將被留下並且ID 5將是正確的)。但是,每個左右對之間有許多沒有配對的唯一ID。我試圖編寫一個查詢來查找表中的所有Left和Right對。

例如(目前這兩個ID和LR是VARCHAR2)

ID LR Identifier 
1 L B15A 
2 R A15C 
3 L A15C 
4 R A15C 
5 L A15C 
6 R D5A2 
9 R D5A2 
10 L E5A6 
11 R E5A6 
12 L E5A6 
13 R E5A6 
14 R H9S5 
17 L EE5A 
18 R EE5A 

,我需要查詢返回

ID LR Identifier 
2 R A15C 
3 L A15C 
4 R A15C 
5 L A15C 
10 L E5A6 
11 R E5A6 
12 L E5A6 
13 R E5A6 
17 L EE5A 
18 R EE5A 

對前一個問題的聯繫是Here。問題是如果我在右邊搜索左邊(反之亦然),我會錯誤地匹配對。因此,查詢必須找到該鏈中的第一標識符和配對,然後隨後的部分,不管它是否是右手或左手例如一個不正確的例子是,如果它存在:

ID LR Identifier 
3 L A15C 
4 R A15C 
10 L E5A6 
11 R E5A6 
12 L E5A6 
13 R E5A6 
17 L EE5A 
18 R EE5A 

任何幫助是非常感謝!先謝謝你。

+0

您正在使用哪種版本的Oracle? – mathguy

+0

另外,讓我們確保需求足夠清晰。你是說如果找到一對,那麼這兩行就會彼此相鄰?或者,一對標識符可能會在幾行之後,而不是在緊隨其後的一行? – mathguy

+0

@mathguy是的,你的第一個陳述是正確的。如果找到一對,則具有相同標識符的零件將會是之前的一個零件號或一個零件號。我也使用Oracle 12.9.0.71 (ps感謝您以前的所有幫助!!這只是...一個永無止境的項目) – mlin

回答

2

這是一個更普遍適用的解決方案,即使這些配對並不一定緊挨在一起。 (如果是實際上必需的,如果部分不能配對,如果他們的ID是不連續的,這一條件可以被添加到查詢中。)

with 
    test_data (id, lr, identifier) as (
     select '001', 'L', 'B15A' from dual union all 
     select '002', 'R', 'A15C' from dual union all 
     select '003', 'L', 'A15C' from dual union all 
     select '004', 'R', 'A15C' from dual union all 
     select '005', 'L', 'A15C' from dual union all 
     select '006', 'R', 'D5A2' from dual union all 
     select '009', 'R', 'D5A2' from dual union all 
     select '010', 'L', 'E5A6' from dual union all 
     select '011', 'R', 'E5A6' from dual union all 
     select '012', 'L', 'E5A6' from dual union all 
     select '013', 'R', 'E5A6' from dual union all 
     select '014', 'R', 'H9S5' from dual union all 
     select '017', 'L', 'EE5A' from dual union all 
     select '018', 'R', 'EE5A' from dual 
    ) 
-- end of test data, the solution (SQL query) begins below this line 
select id, lr, identifier 
from (select id, lr, identifier, 
       row_number() over (partition by identifier, lr order by id) as rn, 
       least(count(case when lr = 'L' then 1 end) over (partition by identifier), 
        count(case when lr = 'R' then 1 end) over (partition by identifier) 
        ) as least_count 
     from test_data 
) 
where rn <= least_count 
order by id    -- ORDER BY is optional 
; 

輸出

ID LR IDENTIFIER 
--- -- ---------- 
002 R A15C 
003 L A15C 
004 R A15C 
005 L A15C 
010 L E5A6 
011 R E5A6 
012 L E5A6 
013 R E5A6 
017 L EE5A 
018 R EE5A 

10 rows selected 

說明:在內部查詢中,我將兩列添加到初始數據。一個,rn,對於每個標識符分開計數(從1開始並遞增1),分別針對'L'和'R'進行計數。這將用於形成對。並且,ct給出了每個標識符的「L」和「R」的總計數中最小的一個。在外部查詢中,我只是篩選出所有行,其中rn > ct - 這些是初始表中沒有配對的行。剩下的是雙。

ADDED:由於必須由「連續」行構成一對(由id列測量),這成爲一個更有趣的問題。這是一個間隙和孤島問題(識別具有相同特徵的連續行的組),但有一個扭曲:值必須在組內交替,而不是恆定。非常有效的「tabibitosan」方法在這裏不能應用(我認爲); 「更多一般」的「組的開始」方法確實起作用。這是我在這裏使用的。請注意,如果組的最後一行是奇數,那麼最後我會排除最後一行。 (我們可以找到兩個,或四個或六個連續的行,它們構成一對或兩對或三對,但不是具有交替LR的奇數行)。還要注意的是,如果兩行具有相同的標識符AND LR,則第二行將始終啓動一個NEW組,因此如果它實際上是一對(與該行之後的行)的一部分,則該解決方案將正確捕獲該行。

將此與Oracle 12及更高版本的MATCH_RECOGNIZE解決方案進行比較,我單獨發佈了這些解決方案 - 並且明白它有多簡單!

with 
    prep (id, lr, identifier, flag) as (
     select id, lr, identifier, 
       case when identifier = lag(identifier) over (order by id) 
        and lr  != lag(lr)   over (order by id) 
        then null else 1 end 
     from test_data -- replace "test_data" with actual table name 
    ), 
    with_groups (id, lr, identifier, gp) as (
     select id, lr, identifier, 
       sum(flag) over (order by id) 
     from prep 
    ), 
    with_rn (id, lr, identifier, rn, ct) as (
     select id, lr, identifier, 
       row_number() over (partition by identifier, gp order by id), 
       count(*)  over (partition by identifier, gp) 
     from with_groups 
    ) 
select id, lr, identifier 
from  with_rn 
where rn < ct or mod(rn, 2) = 0 
order by id    -- ORDER BY is optional 
; 
+0

感謝您的快速響應!對於這個項目,對於不連續的零件可以有相同的標識符,但不是正確配對的零件。你可以添加ID必須連續的條件嗎?再次感謝。 – mlin

+0

@mlin - 好的。如果你有三個連續的行有相同的IDENTIFIER,那麼應該發生什麼,L,R,L?只顯示前兩個,並且只顯示最後一個,如果它與具有相同IDENTIFIER且LR = R的第四行配對?我假設如此,但肯定知道。 – mathguy

+0

是的你是對的。如果連續三行具有相同的IDENTIFIER,即L,R,L(或R,L,R),則只顯示前兩個。 – mlin

0

爲了完整,以下是使用Oracle 12.1及更高版本MATCH_RECOGNIZE子句的答案。 (目前它對OP沒有幫助,他在11.2上,但它可能在未來幫助其他人。)它假定附加條件,即只有在原始表中連續的行形成一對。

select id, lr, identifier 
from test_data -- replace "test_data" with the actual table name 
match_recognize (
    order by id 
    all rows per match 
    pattern (A B) 
    define B as B.identifier = A.identifier and B.lr != A.lr 
) 
order by id    -- ORDER BY is optional 
;