Sql 具有管道符号的Oracle比较表内容
我在oracle中遇到以下问题,正在寻找解决方案。 我想比较两个表的内容,但内容格式彼此不同Sql 具有管道符号的Oracle比较表内容,sql,oracle,Sql,Oracle,我在oracle中遇到以下问题,正在寻找解决方案。 我想比较两个表的内容,但内容格式彼此不同 Table CANON CAN 18102-75|18103-0|18104-88 Table DRUM DR 18103-0 我必须比较这两个表,结果应该是18102-75和18104-88 目前,我有一个简单使用等于的例子,结果很奇怪 CASE WHEN (CANON .CAN = DRUM .DR) THEN NULL -- not showing if they are the
Table CANON
CAN
18102-75|18103-0|18104-88
Table DRUM
DR
18103-0
我必须比较这两个表,结果应该是18102-75和18104-88
目前,我有一个简单使用等于的例子,结果很奇怪
CASE WHEN (CANON .CAN = DRUM .DR)
THEN NULL -- not showing if they are the same
ELSE CANON .CAN
END
有些事我不明白 如果同一记录中有更多的值,用|字符分隔,则可以定义(例如)一个PL/SQL函数,用于转换表中的字符串,然后在查询中使用它:
CREATE OR REPLACE TYPE T_CHARACTERS_NESTED_TABLE AS TABLE OF VARCHAR2(10);
/
CREATE OR REPLACE FUNCTION STRING_TO_NESTED_TABLE
(pStringOfCharacters IN VARCHAR2)
RETURN T_CHARACTERS_NESTED_TABLE
PIPELINED
AS
myStringOfCharacters VARCHAR2(32767) DEFAULT pStringOfCharacters || '|';
myPos NUMBER;
BEGIN
LOOP
myPos := INSTR(myStringOfCharacters, '|');
EXIT WHEN NVL(myPos, 0) = 0;
PIPE ROW(TRIM(SUBSTR(myStringOfCharacters, 1, myPos - 1)));
myStringOfCharacters := SUBSTR(myStringOfCharacters, myPos + 1);
END LOOP;
RETURN;
END STRING_TO_NESTED_TABLE;
/
然后:
SELECT CAN
FROM (SELECT T.COLUMN_VALUE AS CAN
FROM CANON C,
TABLE(STRING_TO_NESTED_TABLE(C.CAN)) T)
WHERE CAN NOT IN (SELECT DR
FROM DRUM
WHERE DR IS NOT NULL);
子查询中DR不为NULL的条件会阻止您获取空的结果集,以防DR列中可能有NULL。这应该可以做到这一点
select *
from (select substr(can, 1, instr(can, '|', 1, 1) - 1) as can,
case
when level = 1 then
replace(substr(can, 1, instr(can, '|', 1, 1)), '|', '')
else
replace(substr(can,
instr(can, '|', 1, level),
length(can) - instr(can, '|', 1, level)),
'|',
'')
end as drum
from canon
connect by level <= (length(can) - length(replace(can, '|')))
and prior sys_guid() is not null
and prior can = can) x
where not exists (select 'x' from drum y where y.dr = x.drum)
order by 1, 2
SQL Fiddle演示:
注意:出于测试目的,我在两个表中的每个表上都添加了第二行,因为我想确保它对2+行有效,因为逻辑对此很敏感
作为对您问题的第二个回答,如果您希望将数据放在同一行上,尽管我认为我的第一个查询更有意义,但这将为您提供您要求的确切结果,即将CAN的每个值的所有值放在同一行上:
select can||'|'||listagg(drum,'|') within group (order by drum) as listed
from (select substr(can, 1, instr(can, '|', 1, 1) - 1) as can,
case
when level = 1 then
replace(substr(can, 1, instr(can, '|', 1, 1)), '|', '')
else
replace(substr(can,
instr(can, '|', 1, level),
length(can) - instr(can, '|', 1, level)),
'|',
'')
end as drum
from canon
connect by level <= (length(can) - length(replace(can, '|')))
and prior sys_guid() is not null
and prior can = can) x
where not exists (select 'x' from drum y where y.dr = x.drum)
group by can
order by 1
你总是在寻找佳能里的东西,而不是鼓里的吗?并非相反,也只是为了更好地理解这一点,相机的第一个标识符“18102-75”是否与下两个兼容?它是否会在所有的佳能行上遵循相同的格式;第一个ID是相机,然后是每个由管道隔开的兼容鼓?是的,我想从佳能表中获取数据。有时佳能只有一位数的CAN no。请注意,在结果集中,每个鼓都位于单独的一行。这是因为为了得到您的解决方案,我必须将您的单行拆分为多行,这可能是它们应该如何存储的。如果出于任何原因,必须将它们放在结果集中的同一行上,则可以使用LISTAGG。只是想知道,当有更多管道分隔值时,这会起作用吗?是的,connect by子句用于将行拆分为多行,但应根据每个字符串中管道的数量创建多行。因此,如果在你的例子中,佳能的一排上有5个鼓,那么这一排就有5个鼓了。在下一行中,如果分隔列表中有3个,则为3。