2017-05-24 66 views
0

我想比較表-1的columnn-A和表-2的B列。都有逗號分隔值。
在我的情況下,如果列B中的所有值都存在列A中,我必須返回TRUE
否則爲false。請指教。例如:比較兩個不同oracle表中的2個逗號分隔列

1.Column A已經A,B,C,DEF列B有A,C,B其應返回TRUE
2.柱1具有VVV,CCC,RR柱2具有CCC,RR, 125應該返回FALSE
3.第1列空,第2列有null,則應該返回TRUE

請幫

+0

嘛,你嘗試過什麼? – OldProgrammer

+4

當前的表格設計打破了第一種正常形式,每個值應該是原子*(每個值單獨的字段或行,而不是將它們填入單個字符串)*。我強烈建議修復設計。 (這種設計讓世界受到傷害。) – MatBailie

+0

你的例子不僅打破了良好的設計原則,而且打破了三值邏輯的基本規則。 NULL永遠不會等於任何東西,包括NULL。任何與NULL的比較都不會返回TRUE或FALSE,而是返回NULL。基本上你在這裏得到的是通常所說的「製造中的災難」。所有這些關係設計規則,以及所有關於「規範化」和東西的東西?是的 - 這是爲了防止你犯這種錯誤。不要這樣做! (如果這是一次課堂練習,我有權告訴你的老師這是一個非常糟糕的例子,祝你好運)。 –

回答

0

希望這個片段幫助。

SELECT DECODE(NULLIF(
    (SELECT LISTAGG(x.col_val,',') WITHIN GROUP(
    ORDER BY x.col_val)intrsctnVal 
    FROM 
    (SELECT SUBSTR(REPLACE(COL2,',',''),LEVEL,1) col_val 
    FROM 
     (SELECT 'a,b,c' AS COL2 FROM DUAL 
    )B 
     CONNECT BY level <= regexp_count(col2,',')+1 
    INTERSECT 
    SELECT SUBSTR(REPLACE(COL1,',',''),LEVEL,1) col_val 
    FROM 
     (SELECT 'a,b,c,d' AS COL1 FROM DUAL 
    )A 
     CONNECT BY LEVEL <= REGEXP_COUNT(COL1,',')+1 
    )X 
), 
    (SELECT 'a,b,c' AS COL2 FROM DUAL 
)),NULL,'TRUE','FALSE') MATCH 
FROM DUAL; 
+1

現在做這些值來自兩個表被連接在一起?它是可以做到的,但是很混亂,複雜而且很慢(同一個連接重複多次)。 – MatBailie

+0

我們一直希望這會有所幫助,但一些額外的筆記可能會大大增加其實際幫助的可能性。 – miracle173

+0

非常感謝,很抱歉沒有看到它,我的appologies。 – Arch

0

最終,我知道了) 這是一個有趣的任務對我來說,只使用SQL解決它:

  B   N SORTED                   BOOL 
---------- ---------- -------------------------------------------------------------------------------- ----- 
     1   1 [a],[b],[c]                  true 
     1   2 [ccc],[rr],[vvv]                 false 
     1   3 []                    true 

1步:聯盟兩個表:

SQL> with 
    2 t1 as (
    3 select 1 n, 'c,b,a' c from dual 
    4 union all 
    5 select 2 n, 'vvv,ccc,rr' c from dual 
    6 union all 
    7 select 3 n, null c from dual), 
    8 t2 as (
    9 select 1 n, 'a,b,c' c from dual 
10 union all 
11 select 2 n, 'ccc,rr,125' c from dual 
12 union all 
13 select 3 n, null c from dual), 
14 t12 as (select 1 b, n, c from t1 union all select 2 b, n, c from t2) 
15 select * from t12 
16/

     B   N C 
---------- ---------- ---------- 
     1   1 c,b,a 
     1   2 vvv,ccc,rr 
     1   3 
     2   1 a,b,c 
     2   2 ccc,rr,125 
     2   3 

6 rows selected 

2步:計數分隔符:

SQL> with 
    2 t1 as (
    3 select 1 n, 'c,b,a' c from dual 
    4 union all 
    5 select 2 n, 'vvv,ccc,rr' c from dual 
    6 union all 
    7 select 3 n, null c from dual), 
    8 t2 as (
    9 select 1 n, 'a,b,c' c from dual 
10 union all 
11 select 2 n, 'ccc,rr,125' c from dual 
12 union all 
13 select 3 n, null c from dual), 
14 t12 as (select 1 b, n, c from t1 union all select 2 b, n, c from t2), 
15 t as (select b, n, c, nvl(length(regexp_replace(c, '[^,]+')) + 1, 1) cnt from t12) 
16 select * from t 
17/

     B   N C     CNT 
---------- ---------- ---------- ---------- 
     1   1 c,b,a    3 
     1   2 vvv,ccc,rr   3 
     1   3      1 
     2   1 a,b,c    3 
     2   2 ccc,rr,125   3 
     2   3      1 

6 rows selected 

3步驟:計算值邊界值

SQL> with 
    2 t1 as (
    3 select 1 n, 'c,b,a' c from dual 
    4 union all 
    5 select 2 n, 'vvv,ccc,rr' c from dual 
    6 union all 
    7 select 3 n, null c from dual), 
    8 t2 as (
    9 select 1 n, 'a,b,c' c from dual 
10 union all 
11 select 2 n, 'ccc,rr,125' c from dual 
12 union all 
13 select 3 n, null c from dual), 
14 t12 as (select 1 b, n, c from t1 union all select 2 b, n, c from t2), 
15 t as (select b, n, c, nvl(length(regexp_replace(c, '[^,]+')) + 1, 1) cnt from t12), 
16 tbrd as (select b, n, c, cnt, sum(cnt) over (order by b,n) brd from t) 
17 select * from tbrd 
18/

     B   N C     CNT  BRD 
---------- ---------- ---------- ---------- ---------- 
     1   1 c,b,a    3   3 
     1   2 vvv,ccc,rr   3   6 
     1   3      1   7 
     2   1 a,b,c    3   10 
     2   2 ccc,rr,125   3   13 
     2   3      1   14 

6 rows selected 

4步驟:產生用於行

SQL> with 
    2 t1 as (
    3 select 1 n, 'c,b,a' c from dual 
    4 union all 
    5 select 2 n, 'vvv,ccc,rr' c from dual 
    6 union all 
    7 select 3 n, null c from dual), 
    8 t2 as (
    9 select 1 n, 'a,b,c' c from dual 
10 union all 
11 select 2 n, 'ccc,rr,125' c from dual 
12 union all 
13 select 3 n, null c from dual), 
14 t12 as (select 1 b, n, c from t1 union all select 2 b, n, c from t2), 
15 t as (select b, n, c, nvl(length(regexp_replace(c, '[^,]+')) + 1, 1) cnt from t12), 
16 tbrd as (select b, n, c, cnt, sum(cnt) over (order by b,n) brd from t), 
17 allrec as (select level lv from dual connect by level <= (select sum(cnt) from t)) 
18 select * from allrec 
19/

     LV 
---------- 
     1 
     2 
     3 
     4 
     5 
     6 
     7 
     8 
     9 
     10 
     11 
     12 
     13 
     14 

14 rows selected 

5步驟新的查詢:主查詢

SQL> with 
    2 t1 as (
    3 select 1 n, 'c,b,a' c from dual 
    4 union all 
    5 select 2 n, 'vvv,ccc,rr' c from dual 
    6 union all 
    7 select 3 n, null c from dual), 
    8 t2 as (
    9 select 1 n, 'a,b,c' c from dual 
10 union all 
11 select 2 n, 'ccc,rr,125' c from dual 
12 union all 
13 select 3 n, null c from dual), 
14 t12 as (select 1 b, n, c from t1 union all select 2 b, n, c from t2), 
15 t as (select b, n, c, nvl(length(regexp_replace(c, '[^,]+')) + 1, 1) cnt from t12), 
16 tbrd as (select b, n, c, cnt, sum(cnt) over (order by b,n) brd from t), 
17 allrec as (select level lv from dual connect by level <= (select sum(cnt) from t)), 
18 step5 as (select r.b, r.n, r.c, regexp_substr(c, '[^,]+', 1, r.brd - a.lv + 1) s from tbrd r, allrec a 
19 where r.brd - a.lv between 0 and r.cnt - 1) 
20 select * from step5 
21/

     B   N C   S 
---------- ---------- ---------- ---------- 
     1   1 c,b,a  a 
     1   1 c,b,a  b 
     1   1 c,b,a  c 
     1   2 vvv,ccc,rr rr 
     1   2 vvv,ccc,rr ccc 
     1   2 vvv,ccc,rr vvv 
     1   3    
     2   1 a,b,c  c 
     2   1 a,b,c  b 
     2   1 a,b,c  a 
     2   2 ccc,rr,125 125 
     2   2 ccc,rr,125 rr 
     2   2 ccc,rr,125 ccc 
     2   3    

14 rows selected 

6步驟:排序值

SQL> with 
    2 t1 as (
    3 select 1 n, 'c,b,a' c from dual 
    4 union all 
    5 select 2 n, 'vvv,ccc,rr' c from dual 
    6 union all 
    7 select 3 n, null c from dual), 
    8 t2 as (
    9 select 1 n, 'a,b,c' c from dual 
10 union all 
11 select 2 n, 'ccc,rr,125' c from dual 
12 union all 
13 select 3 n, null c from dual), 
14 t12 as (select 1 b, n, c from t1 union all select 2 b, n, c from t2), 
15 t as (select b, n, c, nvl(length(regexp_replace(c, '[^,]+')) + 1, 1) cnt from t12), 
16 tbrd as (select b, n, c, cnt, sum(cnt) over (order by b,n) brd from t), 
17 allrec as (select level lv from dual connect by level <= (select sum(cnt) from t)), 
18 step5 as (select r.b, r.n, r.c, regexp_substr(c, '[^,]+', 1, r.brd - a.lv + 1) s from tbrd r, allrec a 
19 where r.brd - a.lv between 0 and r.cnt - 1), 
20 step6 as (
21 select b, n, listagg('[' || s || ']', ',') within group (order by s) sorted 
22 from step5 
23 group by b, n) 
24 select * from step6 
25/

     B   N SORTED 
---------- ---------- -------------------------------------------------------------------------------- 
     1   1 [a],[b],[c] 
     1   2 [ccc],[rr],[vvv] 
     1   3 [] 
     2   1 [a],[b],[c] 
     2   2 [125],[ccc],[rr] 
     2   3 [] 

6 rows selected 

7步:重新當然,使用函數好得多,但是,我只是想找到一種只使用SQL的方法。

(2017年6月5日:新增功能)

功能可以是:

create or replace function comparesepval(vArg1 in varchar2, vArg2 in varchar2) return number result_cache deterministic 
as 
    type tpStore is table of number index by varchar2(32); 

    tStore1 tpStore; 
    tStore2 tpStore; 
    nCnt number; 
    vVal varchar2(32); 
begin 
    if (vArg1 is null and vArg2 is null) or (vArg1 = vArg2) then 
    return 1; 
    end if; 

    if vArg1 is null then 
    return 0; 
    end if; 

    nCnt := nvl(length(regexp_replace(vArg1, '[^,]+')), 0) + 1; 

    if nCnt = 1 or nCnt <> nvl(length(regexp_replace(vArg2, '[^,]+')), 0) + 1 then -- vArg1 <> vArg2 
    return 0; 
    end if; 

    -- parse string 
    for i in 1..nCnt 
    loop 
    declare 

     procedure prcAgr(vArg in varchar2, tStore in out tpStore) 
     as 
     vVal varchar2(32) := nvl(regexp_substr(vArg, '(.*?)(,|$)', 1, i, null, 1), ','); -- ',' - for null 
     begin 
     tStore(vVal) := case when tStore.exists(vVal) then tStore(vVal) + 1 else 1 end; 
     end; 

    begin 
     prcAgr(vArg1, tStore1); 
     prcAgr(vArg2, tStore2); 
    end; 
    end loop; 

    if tStore1.count <> tStore2.count then 
    return 0; 
    end if; 

    vVal := tStore1.first; 
    loop 
    exit when vVal is null; 
    if not tStore2.exists(vVal) then 
     return 0; 
    end if; 
    if tStore2(vVal) <> tStore1(vVal) then 
     return 0; 
    end if; 
    vVal := tStore1.next(vVal); 
    end loop; 

    return 1; 
end; 
/

測試:

SQL> with tbl as (
    2 select null c1, null c2 from dual union all 
    3 select 'a' c1, 'a' c2 from dual union all 
    4 select 'a' c1, 'b' c2 from dual union all 
    5 select 'a,a' c1, 'a,b' c2 from dual union all 
    6 select 'a,a' c1, 'a,b,a' c2 from dual union all 
    7 select 'a,a,b' c1, 'a,b,a' c2 from dual union all 
    8 select 'a,,b' c1, ',b,a' c2 from dual union all 
    9 select 'a,' c1, 'd,' c2 from dual 
10 ) 
11 select comparesepval(c1, c2) c, c1, c2 from tbl; 

     C C1 C2 
---------- ----- ----- 
     1  
     1 a  a 
     0 a  b 
     0 a,a a,b 
     0 a,a a,b,a 
     1 a,a,b a,b,a 
     1 a,,b ,b,a 
     0 a, d, 

8 rows selected 
+0

不要使用「[^,] +」'形式的正則表達式來分析分隔字符串。如果有一個NULL元素,它將失敗。在這裏看到更多的信息:https://stackoverflow.com/a/31464699/2543416 –

+0

這讓我感到驚訝。謝謝,@Gary_W – saphsys

+0

這對我來說也是!我發現生產報告中的一個錯誤報告了錯誤的數據(我們有一個供應商系統超出了我們的控制範圍,其列包含逗號分隔值列表)。現在我正在執行一項任務,告誡人們。不好的部分是,這是在尋找如何解析分隔列表的人的回覆中找到的常見正則表達式。加入我的使命! –