【问题标题】:How to compare 2 columns and return the difference in oracle SQL如何比较 2 列并返回 oracle SQL 中的差异
【发布时间】:2021-08-13 19:06:45
【问题描述】:

我们在 oracle SQL 中的一张表中有 2 列 Col1="桌子上有书" Col2= "椅子上有花" 现在我需要将结果作为 column3 中的不同数据作为新列 col3。 col3 结果应该是 “都是花椅”。 如何在 oracle SQL 中实现这一点??

【问题讨论】:

  • 这不是您通常会在 SQL 中解决的任务。如果您对单词感兴趣,您会将单词存储在数据库中,而不是像您所做的那样存储多单词字符串。编程语言将更适合该任务(例如 PL/SQL)。如果要在 SQL 中执行此操作,则应使用递归查询来循环单词。
  • 如果两个字符串是“你妈妈穿着军靴”和“我圣诞节想要的只是我的两颗门牙”怎么办?

标签: oracle


【解决方案1】:

你可以使用:

WITH words ( rid, col, name, id, word ) AS (
  SELECT rid,
         CASE INSTR(col, ' ')
         WHEN 0
         THEN NULL
         ELSE SUBSTR(col, INSTR(col, ' ') + 1)
         END,
         name,
         1,
         CASE INSTR(col, ' ')
         WHEN 0
         THEN col
         ELSE SUBSTR(col, 1, INSTR(col, ' ') - 1)
         END
  FROM   ( SELECT ROWID AS rid, col1, col2 FROM table_name )
  UNPIVOT ( col FOR name IN (col1, col2) )
UNION ALL
  SELECT rid,
         CASE INSTR(col, ' ')
         WHEN 0
         THEN NULL
         ELSE SUBSTR(col, INSTR(col, ' ') + 1)
         END,
         name,
         id + 1,
         CASE INSTR(col, ' ')
         WHEN 0
         THEN col
         ELSE SUBSTR(col, 1, INSTR(col, ' ') - 1)
         END
  FROM   words
  WHERE col IS NOT NULL
),
paired_words ( rid, id1, id2 ) AS (
  SELECT c1.rid,
         c1.id AS id1,
         c2.id AS id2
  FROM   ( SELECT rid, id, word FROM words WHERE name = 'COL1' ) c1
         INNER JOIN
         ( SELECT rid, id, word FROM words WHERE name = 'COL2' ) c2
         ON (c1.rid = c2.rid AND c1.word = c2.word)
),
max_path ( rid, path ) AS (
  SELECT rid,
         path
  FROM   (
    SELECT rid,
           SYS_CONNECT_BY_PATH(id2, ',') || ',' AS path,
           ROW_NUMBER() OVER (PARTITION BY rid ORDER BY LEVEL DESC) AS rn
    FROM   paired_words
    CONNECT BY PRIOR rid = rid
    AND    PRIOR id1 < id1
    AND    PRIOR id2 < id2
  )
  WHERE  rn = 1
)
SELECT LISTAGG(word, ' ') WITHIN GROUP (ORDER BY id) AS missing
FROM   words w
WHERE  NOT EXISTS (
         SELECT 1
         FROM   max_path mp
         WHERE  w.rid = mp.rid
         AND    mp.path LIKE '%,' || w.id || ',%'
       )
AND    w.name = 'COL2'
GROUP BY rid;

其中,对于样本数据:

CREATE TABLE table_name ( col1, col2 ) AS
SELECT 'there is book on the table', 'there are flowers on the chair' FROM DUAL UNION ALL
SELECT 'there is book on the table', 'there is a book on the table' FROM DUAL UNION ALL
SELECT 'there is book on the table', 'there is book there is book on the table on the table' FROM DUAL

输出:

MISSING
are flowers chair
a
there is book on the table

db小提琴here

【讨论】:

  • 感谢@MT0 的快速响应...这里我们还需要关于订单的差异...例如 Col1 为“Thomas Alva Edison”,Col2 为“Alva Thomas Edison 科学家”预期结果是“阿尔瓦·托马斯科学家”……但从您建议的查询中,结果是“托马斯科学家”……如何实现这一目标?抱歉,如果我在解释我的问题时造成任何混淆
【解决方案2】:

这是一个选项(按照您的要求)。在代码中读取 cmets。

SQL> with test (id, col1, col2) as
  2    (select 1, 'there is book on the table',
  3               'there are flowers on the chair'
  4     from dual
  5    ),
  6  -- split sentences into words (each in its own line)
  7  sent1 as
  8    (select id,
  9         column_value cv,
 10         regexp_substr(col1, '[^ ]+', 1, column_value) word
 11     from test cross join
 12       table(cast(multiset(select level from dual
 13                           connect by level <= regexp_count(col1, ' ') + 1
 14                          ) as sys.odcinumberlist))
 15    ),
 16  sent2 as
 17    (select id,
 18         column_value cv,
 19         regexp_substr(col2, '[^ ]+', 1, column_value) word
 20     from test cross join
 21       table(cast(multiset(select level from dual
 22                           connect by level <= regexp_count(col2, ' ') + 1
 23                          ) as sys.odcinumberlist))
 24    )
 25  -- final result
 26  select a.id,
 27         listagg(b.word, ' ') within group (order by a.cv) result
 28  from sent2 b join sent1 a on a.id = b.id and a.cv = b.cv and a.word <> b.word
 29  group by a.id;

        ID RESULT
---------- ------------------------------
         1 are flowers chair

SQL>

【讨论】:

  • 如果您添加一个单词db<>fiddle,这不会给出预期的差异。它也不适用于多行;不过,您只需要在末尾添加 GROUP BY a.id 即可解决后一个问题。
  • 好吧,正如我所说,它遵循问题中所说的内容。从 ID ... 天哪,我拖动它通过所有代码并忘记添加以将其添加到最终 SELECT。谢谢你,@MT0。
猜你喜欢
  • 1970-01-01
  • 2020-04-02
  • 2014-02-26
  • 2019-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多