2011-09-07 5 views

Répondre

0

Je préfère généralement utiliser l'opérateur MULTISET pour des situations comme celle-ci. La solution ci-dessous n'est pas exactement élégante, mais vous devez utiliser la chaîne pour utiliser l'opérateur MULTISET, mais si vous obtenez les listes en tant que collections, ce serait très facile (ou si vous avez déjà un tokenizer commun). (Le tokenizer ci-dessous est pas très rapide.)

DECLARE 
    TYPE VARCHARTABLE IS TABLE OF VARCHAR2(2000); 

    A VARCHAR2(32767) := 'a1, b4, g3, h6, t8, a0'; 
    B VARCHAR2(32767) := 'b4, h6, a0, t8, a1'; 

    onlyInA VARCHARTABLE; 
    onlyInB VARCHARTABLE; 

    FUNCTION tokenize(v IN VARCHAR2) 
    RETURN VARCHARTABLE 
    IS 
     mReturn VARCHARTABLE := VARCHARTABLE(); 
     mTemp VARCHAR2(2000); 
     mChar VARCHAR2(1); 
     mIdx INTEGER := 1; 

     PROCEDURE appendToken(token IN VARCHAR2) 
     IS 
     BEGIN 
     IF TRIM(token) IS NOT NULL THEN 
      mReturn.EXTEND(1); 
      mReturn(mReturn.LAST) := TRIM(token); 
     END IF; 
     END appendToken; 
    BEGIN 
     LOOP 
     mChar := SUBSTR(v, mIdx, 1); 

     IF mChar = ',' THEN 
       appendToken(mTemp); 
       mTemp := NULL; 
     ELSIF mChar IS NULL THEN 
      appendToken(mTemp); 
      EXIT; 
     ELSE 
      mTemp := mTemp || mChar; 
     END IF; 

     mIdx := mIdx + 1; 
     END LOOP; 

     RETURN mReturn; 
    END tokenize; 

    FUNCTION toVarchar(v IN VARCHARTABLE) 
    RETURN VARCHAR2 
    IS 
    mReturn VARCHAR2(32767); 
    mIdx INTEGER := 0; 
    BEGIN 
    mIdx := v.FIRST; 

    WHILE mIdx IS NOT NULL LOOP 
     IF mReturn IS NOT NULL THEN 
      mReturn := mReturn || ','; 
     END IF; 
     mReturn := mReturn || v(mIdx); 

     mIdx := v.NEXT(mIdx); 
    END LOOP; 

    RETURN mReturn; 
    END toVarchar; 
BEGIN 
    onlyInA := tokenize(A) MULTISET EXCEPT tokenize(B); 
    onlyInB := tokenize(B) MULTISET EXCEPT tokenize(A); 

    DBMS_OUTPUT.put_line('Only in A : ' || toVarchar(onlyInA)); 
    DBMS_OUTPUT.put_line('Only in B : ' || toVarchar(onlyInB)); 
END; 
+0

Génial - merci! – user813345

1

ne suis pas sûr élégant mais cela fonctionnerait:

WITH t1 AS (SELECT 'a1, b4, g3, h6, t8, a0' str FROM dual), 
    t2 AS (SELECT 'b4, h6, a0, t8, a1' str  FROM dual) 
-- 
SELECT val 
    FROM t1, 
     xmltable('/root/e/text()' 
     passing xmltype('<root><e>' || 
         replace(t1.str,', ','</e><e>') || 
         '</e></root>') 
     columns val varchar2(10) path '/') 
MINUS 
SELECT val 
    FROM t2, 
     xmltable('/root/e/text()' 
     passing xmltype('<root><e>' || 
         replace(t2.str,', ','</e><e>') || 
         '</e></root>') 
     columns val varchar2(10) path '/') 

espérons que cette aide

0

Si vous savez qu'ils vont être des virgules et/ou dans l'espace délimité alors cela fonctionnerait et est beaucoup plus simple.

create or replace function compare_strings (PString1 char, Pstring2 char) return char is 

    v_string1 varchar2(100) := replace(replace(Pstring1,',',''),' ',''); 
    v_string2 varchar2(100) := replace(replace(Pstring2,',',''),' ',''); 

begin 

    if replace(translate(v_string1, v_string2, ' '), ' ', '') is null then 
     return replace(translate(v_string2, v_string1, ' '), ' ', '') ; 
    else 
     return replace(translate(v_string1, v_string2, ' '), ' ', ''); 
    end if; 

end; 

EDIT: modification pour renvoyer la chaîne.

+0

Mais cela ne rend pas vraiment la différence - juste s'il y a une différence? – user813345

+0

Je l'ai changé pour le faire. – Ben

Questions connexes