Frage

Gibt es eine einfache elegante Methode, um den Unterschied zwischen zwei ungeordneten, abgrenzten Zeichenfolgen in Oracle mit PL/SQL zurückzubringen?

Beispiel:

String A: "a1, b4, g3, h6, t8, a0"
String B: "b4, h6, a0, t8, a1"

Unterschied: "G3"

Ich habe keinen Zugriff auf apex_util, wie in dieser Antwort vorgeschlagen Unterschied zwischen zwei ungeordneten deliminierten Listen (Oracle)

War es hilfreich?

Lösung

Normalerweise benutze ich die Verwendung der Multiset Bediener für solche Situationen.

Die folgende Lösung ist jedoch nicht gerade elegant, da Sie die Zeichenfolge tokenisieren müssen, um den Multiset -Operator zu verwenden. Wenn Sie jedoch die Listen als Sammlungen erhalten, wäre dies sehr einfach (oder wenn Sie bereits einen gemeinsamen Tokenizer haben). (Der unten stehende Tokenizer ist nicht sehr schnell.)

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;

Andere Tipps

Ich bin mir nicht sicher über elegante, aber das würde funktionieren:

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 '/')

hoffe das hilft

Wenn Sie wissen, dass sie Komma und / oder Platz abgenommen haben, würde dies funktionieren und ist viel einfacher.

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;

Bearbeiten: Änderung zur Rückgabe der Zeichenfolge.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top