[英]pl sql query to compare 2 columns comma separated values and find differences
COL 1 Values: QQQ,QQ,123,VVVV
COL 2 VALUES: WWWW,VVV,QQQ
比较 COL1 值与 COL 2 值:例如
1)如果 COL1 中存在值但 COL2 中不存在值,则在 COL VALUE ADDED 下显示该 COL1 值
Output 预期: COL VALUE ADDED = QQ,123,VVVV
2)如果 COL2 中存在值但 COL1 中不存在,则在删除的 COL VALUE 下显示该 COL2 值。
Output 预期: COL VALUE REMOVED = WWWW,VVV
3)如果 COL1 和 COL2 中的值集相同,则显示为 NULL
这些是否可以通过 PLSQL 命令按预期动态处理和比较? 我希望有动态的逗号分隔值,需要在当前和之前的值集之间进行比较。
这是一个选项:
SQL> with
2 test (col1, col2) as
3 (select 'QQQ,QQ,123,VVVV', 'WWWW,VVV,QQQ' from dual
4 ),
5 t1 (col) as
6 (select regexp_substr(col1, '[^,]+', 1, level)
7 from test
8 connect by level <= regexp_count(col1, ',') + 1
9 ),
10 t2 (col) as
11 (select regexp_substr(col2, '[^,]+', 1, level)
12 from test
13 connect by level <= regexp_count(col2, ',') + 1
14 ),
15 one_minus_two as
16 (select col from t1
17 minus
18 select col from t2
19 ),
20 two_minus_one as
21 (select col from t2
22 minus
23 select col from t1
24 )
25 select 'Col value added: ' ||
26 listagg(col, ',') within group (order by null) as result
27 from one_minus_two
28 union all
29 select 'Col value removed: ' ||
30 listagg(col, ',') within group (order by null)
31 from two_minus_one
32 union all
33 select 'NULL'
34 from dual
35 where (select listagg(col, ',') within group (order by col) from t1) =
36 (select listagg(col, ',') within group (order by col) from t2);
RESULT
--------------------------------------------------------------------------------
Col value added: 123,QQ,VVVV
Col value removed: VVV,WWWW
SQL>
如果两个值相等:
SQL> with
2 test (col1, col2) as
3 (select 'AAA,BBB,CCC', 'CCC,AAA,BBB' from dual
4 ),
<SNIP>
35 where (select listagg(col, ',') within group (order by col) from t1) =
36 (select listagg(col, ',') within group (order by col) from t2);
RESULT
--------------------------------------------------------------------------------
Col value added:
Col value removed:
NULL
SQL>
这是解决它的一种方法:
WITH cteData AS (SELECT 'QQQ,QQ,123,VVVV' AS COL1,
'WWWW,VVV,QQQ' AS COL2
FROM DUAL),
cteCol1 AS (SELECT REGEXP_SUBSTR(COL1, '[^,]+', 1, LEVEL) AS COL1
FROM cteData
CONNECT BY LEVEL < REGEXP_COUNT(COL1, ',')+2),
cteCol2 AS (SELECT REGEXP_SUBSTR(COL2, '[^,]+', 1, LEVEL) AS COL2
FROM cteData
CONNECT BY LEVEL < REGEXP_COUNT(COL2, ',')+2),
cteAdded AS (SELECT c1.COL1 -- COL1 not found in COL2
FROM cteCol1 c1
WHERE c1.COL1 NOT IN (SELECT COL2
FROM cteCol2)),
cteRemoved AS (SELECT c2.COL2 -- in COL2 but NOT in COL1
FROM cteCol2 c2
WHERE c2.COL2 NOT IN (SELECT COL1
FROM cteCol1)),
cteAdded_list AS (SELECT LISTAGG(a.COL1, ',') WITHIN GROUP (ORDER BY 1) AS ADDED
FROM cteAdded a),
cteRemoved_list AS (SELECT LISTAGG(r.COL2, ',') WITHIN GROUP (ORDER BY 1) AS REMOVED
FROM cteRemoved r),
cteResults AS (SELECT CASE
WHEN a.ADDED IS NULL THEN NULL
ELSE 'COL VALUE ADDED = ' || a.ADDED
END AS RESULT
FROM cteAdded_list a
UNION ALL
SELECT CASE
WHEN r.REMOVED IS NULL THEN NULL
ELSE 'COL VALUE REMOVED = ' || r.REMOVED
END AS RESULT
FROM cteRemoved_list r)
SELECT RESULT
FROM cteResults
WHERE RESULT IS NOT NULL
使用您提供的数据返回:
COL VALUE ADDED = 123,QQ,VVVV
COL VALUE REMOVED = VVV,WWWW
如果您将cteData
中的字符串替换为相同的字符串,例如将两者都设置为'123,456,789'
则它会返回一个空结果集。
由于您需要 PL/SQL 解决方案,您可以创建 function 将字符串拆分为数组,然后使用MULTISET
运算符:
拆分 Function :
从我之前的回答
CREATE OR REPLACE FUNCTION split_String(
i_str IN VARCHAR2,
i_delim IN VARCHAR2 DEFAULT ','
) RETURN stringlist DETERMINISTIC
AS
p_result stringlist := stringlist();
p_start NUMBER(5) := 1;
p_end NUMBER(5);
c_len CONSTANT NUMBER(5) := LENGTH( i_str );
c_ld CONSTANT NUMBER(5) := LENGTH( i_delim );
BEGIN
IF c_len > 0 THEN
p_end := INSTR( i_str, i_delim, p_start );
WHILE p_end > 0 LOOP
p_result.EXTEND;
p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, p_end - p_start );
p_start := p_end + c_ld;
p_end := INSTR( i_str, i_delim, p_start );
END LOOP;
IF p_start <= c_len + 1 THEN
p_result.EXTEND;
p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, c_len - p_start + 1 );
END IF;
END IF;
RETURN p_result;
END;
/
PL/SQL :
然后你可以在 PL/SQL 块中使用它:
DECLARE
col1 VARCHAR2(4000) := 'QQQ,QQ,123,VVVV';
col2 VARCHAR2(4000) := 'WWWW,VVV,QQQ';
arr1 stringlist := SPLIT_STRING( col1 );
arr2 stringlist := SPLIT_STRING( col2 );
added stringlist := arr1 MULTISET EXCEPT arr2;
removed stringlist := arr2 MULTISET EXCEPT arr1;
BEGIN
FOR i IN 1 .. added.COUNT LOOP
DBMS_OUTPUT.PUT( added(i) || ',' );
END LOOP;
DBMS_OUTPUT.NEW_LINE();
FOR i IN 1 .. removed.COUNT LOOP
DBMS_OUTPUT.PUT( removed(i) || ',' );
END LOOP;
DBMS_OUTPUT.NEW_LINE();
END;
/
哪个输出:
dbms_output: QQ,123,VVVV, WWWW,VVV,
SQL :
如果您想在 SQL 中实现它,那么使用测试数据:
CREATE TABLE test_data ( col1, col2 ) AS
SELECT 'QQQ,QQ,123,VVVV', 'WWWW,VVV,QQQ' FROM DUAL;
您可以使用以下方式查询它:
SELECT ( SELECT LISTAGG( column_value, ',' ) WITHIN GROUP ( ORDER BY ROWNUM )
FROM TABLE( a.arr1 MULTISET EXCEPT a.arr2 ) ) AS added,
( SELECT LISTAGG( column_value, ',' ) WITHIN GROUP ( ORDER BY ROWNUM )
FROM TABLE( a.arr2 MULTISET EXCEPT a.arr1 ) ) AS removed
FROM (
SELECT SPLIT_STRING( col1 ) AS arr1,
SPLIT_STRING( col2 ) AS arr2
FROM test_data
) a;
哪个输出:
已添加 | 已删除:--------- |:-------- QQ,123,VVVV | 万维网,VVV
db<> 在这里摆弄
db<> 在这里摆弄
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.