简体   繁体   English

如何获取另一个 listagg 中不存在的 id | Oracle 19c |

[英]How to get ids which does not exist in another listagg | Oracle 19c |

I have written a query to get values in comma separated format from both the table我编写了一个查询以从两个表中获取逗号分隔格式的值

Table 1:表格1:

SELECT 
    regex_replace(xmlcast(Xmlagg(XMLELEMENT(empid, empid, ',')) AS clob), '\s*,\s*$', '') AS str1
FROM 
    (SELECT empid
     FROM employee);

Table 2:表 2:

SELECT 
    regex_replace(xmlcast(Xmlagg(XMLELEMENT(depid, depid, ',')) AS clob), '\s*,\s*$', '') AS str2
FROM   
    (SELECT depid
     FROM department);

Output of both queries:两个查询的 Output:

str1 = 1,4,5,6,8
str2 = 1,5,6

How do I compare both the str1 and str2 and get ids which are in str1 but not in str2如何比较str1str2并获取在str1但不在str2中的 id

Expected output: 4,8预期 output: 4,8

You do not need to compare the delimited strings, you can simply use NOT IN (or NOT EXISTS ) and compare the table values:您不需要比较分隔字符串,您可以简单地使用NOT IN (或NOT EXISTS )并比较表值:

SELECT regexp_replace( xmlcast(Xmlagg(XMLELEMENT(empid,empid,',')) as clob),'\s*,\s*$','') AS str1
FROM   employee
WHERE  empid NOT IN (
         SELECT depid
         FROM   department
       );

However, you should consider whether it makes sense to compare the IDs for employees to the IDs for departments as that does not appear to make logical sense.但是,您应该考虑将员工的 ID 与部门的 ID 进行比较是否有意义,因为这似乎没有逻辑意义。

For the sample data:对于样本数据:

CREATE TABLE employee (empid) AS
SELECT 1 FROM DUAL UNION ALL
SELECT 4 FROM DUAL UNION ALL
SELECT 5 FROM DUAL UNION ALL
SELECT 6 FROM DUAL UNION ALL
SELECT 8 FROM DUAL;

CREATE TABLE department (depid) AS
SELECT 1 FROM DUAL UNION ALL
SELECT 5 FROM DUAL UNION ALL
SELECT 6 FROM DUAL;

The query outputs:查询输出:

STR1 STR1
4,8 4,8

db<>fiddle here db<> 在这里摆弄

Another approach considering that both str1 and str2 are coming from different tables.考虑到str1str2都来自不同的表的另一种方法。 Although I consider the comments more than right that this kind of comparison should not be done this way.尽管我认为这些评论是正确的,但这种比较不应该以这种方式进行。

with x as 
(
select regexp_substr(x.str1,'[^,]+',1,level) as str1_spit 
from ( select '1,4,5,6,8' as str1 from dual ) x 
CONNECT BY LEVEL <=REGEXP_COUNT(x.str1 ,'[,]') + 1 
), 
y as 
( select regexp_substr(y.str2,'[^,]+',1,level) as str2_spit 
from ( select '1,5,6' as str2 from dual ) y 
CONNECT BY LEVEL <=REGEXP_COUNT(y.str2 ,'[,]') + 1 
)
select LISTAGG(str1_spit, ',') WITHIN GROUP (order by str1_spit) as final_value 
from 
(
select x.str1_spit , y.str2_spit 
from x left join y on x.str1_spit = y.str2_spit 
where y.str2_spit is null
order by x.str1_spit 
)

Demo演示

SQL> with x as
  2  (
select regexp_substr(x.str1,'[^,]+',1,level) as str1_spit
from ( select '1,4,5,6,8' as str1 from dual ) x
CONNECT BY LEVEL <=REGEXP_COUNT(x.str1 ,'[,]') + 1
),
y as
( select regexp_substr(y.str2,'[^,]+',1,level) as str2_spit
from ( select '1,5,6' as str2 from dual ) y
CONNECT BY LEVEL <=REGEXP_COUNT(y.str2 ,'[,]') + 1
)
select LISTAGG(str1_spit, ',') WITHIN GROUP (order by str1_spit) as final_value
from
(
select x.str1_spit , y.str2_spit
from x left join y on x.str1_spit = y.str2_spit
where y.str2_spit is null
order by x.str1_spit
)  3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19  ;

FINAL_VALUE
--------------------------------------------------------------------------------
4,8

SQL>

If you must do it by comparing strings (don't, use NOT IN or NOT EXISTS and compare the tables) then you can do it by only splitting one of the two strings and using simple string functions (rather than regular expressions, which are an order-of-magnitude slower):如果您必须通过比较字符串来做到这一点(不要,使用NOT INNOT EXISTS并比较表),那么您可以通过仅拆分两个字符串之一并使用简单的字符串函数(而不是正则表达式,它们是慢一个数量级):

WITH data (str1, str2) AS (
  SELECT TO_CLOB('1,4,5,6,8'),
         TO_CLOB('1,5,6')
  FROM   DUAL
),
bounds (str1, str2, spos, epos) AS (
  SELECT str1,
         str2,
         1,
         INSTR(str1, ',', 1)
  FROM   data
UNION ALL
  SELECT str1,
         str2,
         epos + 1,
         INSTR(str1, ',', epos + 1)
  FROM   bounds
  WHERE  epos > 0
),
items (item, str2) AS (
  SELECT CASE epos
         WHEN 0
         THEN SUBSTR(str1, spos)
         ELSE SUBSTR(str1, spos, epos - spos)
         END,
         ',' || str2 || ','
  FROM   bounds
  ORDER BY spos
)
SELECT regexp_replace(
         xmlcast(Xmlagg(XMLELEMENT(item,item,',')) as clob),
         '\s*,\s*$'
       ) AS str3
FROM   items
WHERE  str2 NOT LIKE '%,' || item || ',%';

Which outputs:哪个输出:

STR3 STR3
4,8 4,8

db<>fiddle here db<> 在这里摆弄

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM