在两个字符串之间找到不匹配的字母

时间:2014-10-22 06:31:04

标签: sql oracle plsql

我试图编写一个查询,给出两个字符串之间不匹配字母的总数。

例如,我有两个字符串

  

字符串1:Jamess字符串2:Romeeo

我需要找出第二个字符串中不在第一个字符串中匹配的字母总数。

这些信件将是

  

R,o,o和e

(请注意,第一个字符串只有一个e,因此Romeeo中的额外e不会在字符串1中匹配)。

简而言之,这些字母(R,o,o和e)不存在于字符串1中。

是否可以在Oracle SQL中解决此问题?

4 个答案:

答案 0 :(得分:2)

有趣的益智游戏;)

使用分析函数COUNT()并通过分区到当前行,您实际上可以“编号为您的字母”:

  SELECT letters, 
         COUNT(*) OVER (PARTITION BY letters ORDER BY n ROWS 
                        BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) cnt FROM (
    --                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    SELECT SUBSTR('Jameess', LEVEL, 1) letters, LEVEL n FROM DUAL
    CONNECT BY LEVEL <= LENGTH('Jameess')
  )

产生结果:

LETTERS CNT
J       1   -- first J
a       1   -- first a
e       1   -- first e
e       2   -- second e
m       1   -- ...
s       1
s       2

对每个字符串执行一次,您只需将每个字母索引与其自己的组进行比较:

SELECT s2.letters
FROM (
  SELECT letters,
         COUNT(*) OVER (PARTITION BY letters ORDER BY n ROWS 
                        BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) cnt FROM (
    SELECT SUBSTR('Jameess', LEVEL, 1) letters, LEVEL n FROM DUAL
    CONNECT BY LEVEL <= LENGTH('Jameess')
  )
) S1
RIGHT OUTER JOIN (
  SELECT letters, 
         COUNT(*) OVER (PARTITION BY letters ORDER BY n ROWS 
                        BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) cnt FROM (
    SELECT SUBSTR('Romeeeeo', LEVEL, 1) letters, LEVEL n FROM DUAL
    CONNECT BY LEVEL <= LENGTH('Romeeeeo')
  )
) S2
ON s1.letters = s2.letters AND s1.cnt = s2.cnt
WHERE s1.cnt IS NULL
--    ^^^^^^
-- change to `s2.cnt` to compare your strings the other way around 
-- and replace the RIGHT JOIN by a LEFT JOIN
ORDER BY letters

产:

LETTERS
R
e
e
o
o

(出于测试目的,我在eJameess中添加了一些额外的Romeeeeo

答案 1 :(得分:1)

在Oracle

SQL> WITH DATA AS
  2    ( SELECT 'Jamess' str1, 'Romeeo' str2 FROM dual
  3    ),
  4    data2 AS
  5    (SELECT SUBSTR(str1, LEVEL, 1) str1
  6    FROM DATA
  7      CONNECT BY LEVEL <= LENGTH(str1)
  8    ),
  9    data3 AS
 10    (SELECT SUBSTR(str2, LEVEL, 1) str2
 11    FROM DATA
 12      CONNECT BY LEVEL <= LENGTH(str2)
 13    )
 14  SELECT * FROM data3 WHERE str2 NOT IN
 15    (SELECT str1 FROM data2
 16    )
 17  UNION ALL
 18  SELECT str2
 19  FROM data3
 20  WHERE str2 IN
 21    (SELECT str1 FROM data2
 22    )
 23  GROUP BY str2
 24  HAVING COUNT(*)>1
 25  /

S
-
R
o
o
e

SQL>

答案 2 :(得分:0)

问题用[plsql]标记,所以我认为PL / SQL解决方案是有序的:

DECLARE 
  stringA  VARCHAR2(20) := 'Jamess';
  stringB  VARCHAR2(20) := 'Romeeo';
  strDiff  VARCHAR2(20);

  FUNCTION find_unmatched(p1 IN VARCHAR2, p2 IN VARCHAR2)
    RETURN VARCHAR2
  IS
    s1 VARCHAR2(32767) := p1;
    s2 VARCHAR2(32767) := p2;
    s3 VARCHAR2(32767);
    c   CHAR(1);
    p   NUMBER;
  BEGIN
    LOOP
      c := SUBSTR(s2, 1, 1);

      p := INSTR(s1, c);
      IF p = 0 THEN  -- c not found in s1: add to unmatched list and remove from s2
        s3 := s3 || c;
        s2 := SUBSTR(s2, 2);
      ELSE  -- c found in s1: remove from s1 and s2
        s1 := SUBSTR(s1, 1, p-1) || SUBSTR(s1, p+1, LENGTH(s1)-p);
        s2 := SUBSTR(s2, 2);
      END IF;

      IF s1 IS NULL OR s2 IS NULL THEN
        EXIT;
      END IF;
    END LOOP;

    RETURN s3;
  END find_unmatched;

BEGIN
  strDiff := find_unmatched(stringA, stringB);

  DBMS_OUTPUT.PUT_LINE('strDiff=''' || strDiff || '''');
END;

分享并享受。

答案 3 :(得分:-2)

尝试此SQL查询

DECLARE @string1 VARCHAR(100)='Jamess'
DECLARE @string2 VARCHAR(100)='Romeeo'
DECLARE @Notmatchstring VARCHAR(100)
SET @Notmatchstring =''
DECLARE @index INT
DECLARE @count INT

SET @count=1
WHILE @count <= LEN(@string2)
BEGIN

    SET @index=CHARINDEX(SUBSTRING(@string2,@count,1),@string1,0)   

    IF(@index=0)
    BEGIN
    SET @Notmatchstring =@Notmatchstring +' '+SUBSTRING(@string2,@count,1)
    END
    IF(@index>0)
    BEGIN   
    SET @string1=REPLACE(@string1,SUBSTRING(@string2,@count,1),'')
    END
    SET @count=@count+1
END
SELECT @Notmatchstring as NotMatchingCharacter