2014-02-13 14 views
0

我在oracle中遇到以下問題並尋找解決方案。 我想比較兩個表格的內容,但內容格式各不相同。Oracle比較帶有管道符號的表格內容

Table CANON 
CAN 
18102-75|18103-0|18104-88 

Table DRUM 
DR 
18103-0 

我要比較這兩個表,並應得到的結果18102-75和18104-88 目前,我有簡單地使用等於爲例stament,並給它奇怪的結果。

CASE WHEN (CANON .CAN = DRUM .DR) 
    THEN NULL -- not showing if they are the same 
    ELSE CANON .CAN 
END 
+0

您是否一直在尋找CANON中的內容,但不是DRUM中的內容? (而不是相反)也只是爲了更好地理解這一點,是相機的第一個標識符('18102-75'),接下來的2個是兼容的鼓?它會在CANON的所有行上遵循相同的格式嗎?第一個ID是相機,然後是每個兼容的鼓由管道分開? –

+0

是的,我想從CANON表中獲取數據。有些時候佳能只有一位數的CAN號。 – user3095575

回答

0

這應該可以做到。

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小提琴演示:http://sqlfiddle.com/#!4/59a7b/1/0

注:我加在每個2代表的第二行用於測試目的,因爲我想確保它爲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 
+0

請注意,這將每個鼓放在結果集的單獨一行中。那是因爲要得到你的解決方案,我不得不把你的單行分成多行,這可能是他們應該如何存儲。如果出於任何原因必須將它們放在結果集中的同一行上,則可以使用LISTAGG。 –

+0

只有當有更多的管道分隔值時,纔會想到這項工作? – user3095575

+0

是的,使用connect by子句將行分割成多行,但應根據每個字符串中的管道數確定創建多行。因此,如果在您的示例中,CANON的行上有5個鼓,那麼該行會產生5行。在下一行中,如果分隔列表中有3個,則它會變爲3。 –

0

有件事情,我不明白...;)

如果在相同的記錄更多的價值,有獨立「|」字符,你可以定義 - 例如 - 這將您的字符串表中的一個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); 

條件「 WHERE DR IS NOT NULL「在子查詢中阻止您獲得空的結果集,以防您在DR列中可能具有空值。