比较子字符串与多列

时间:2020-03-30 12:06:52

标签: sql oracle sql-like contains unpivot

我有一个表,该表具有20个相似的text属性列,即text1..text20。这些列的类型为CLOB。我正在寻找这些文本属性列之一包含特定短语(例如'%unemployed%')的行。我需要知道2件事,哪些行匹配,哪一列匹配。我以为可以以ANY为起点,但是我遇到了问题。

似乎ANY语句不适用于'%'。例如,

select * from emp where 'BLAKE' = ANY(ename, job); -- Returns Data

但是

select * from emp where '%BLAKE%' = ANY(ename, job) -- No Data Found

执行此操作的正确方法是什么?伪代码就是...

Select name, addr, 
which_column_matched(%unemployed%, text1..text20),
text1..text20
from table
where %unemployed% = ANY(text1..text20);

3 个答案:

答案 0 :(得分:1)

在Oracle中,您可以使用unpivot。仍然需要您枚举所有列,但是语法非常简洁。

如果要为每条匹配的记录提供一条记录:

select *
from emp unpivot (col for src in (text1, text2, text3))
where col like '%unemployed%'

如果您想在匹配列列表中再增加一列,则可以汇总结果集:

select ename, listagg(src, ', ')
from emp unpivot (col for src in (text1, text2, text3))
where col like '%unemployed%'
group by ename

答案 1 :(得分:0)

您可以使用子查询来识别匹配的第一列,然后返回该列:

select t.*
from (select t.*,
             (case when text1 like '%unemployed%' then 'text1'
                   when text2 like '%unemployed%' then 'text2'
                   . . .
                   when text20 like '%unemployed%' then 'text20'
              end) as col_match
      from t
     ) t
where col_match is not null;

答案 2 :(得分:0)

我一直很担心Oracle如何处理CLOB数据,因此下面的测试表明Pivot解决方案应该可以解决问题。

drop table emptest;

-- Assuming we are using the venerable EMP table
create table emptest as select * from emp;

alter table emptest add(
  text1 CLOB,
  text2 CLOB,
  text3 CLOB
)
/

declare
  v_text clob;
begin
  -- set one column to a length well beyond 16k but below 32k, max VARCHAR2 for PL/SQL
  v_text := lpad('X', 16000, 'X')||' unemployed ' || lpad('X', 10000, 'X');
  update emptest set text2 = v_text where ename = 'SMITH';
  -- set others to short values
  v_text := 'an unemployed salesman in text 1';
  update emptest set text1 = v_text where ename = 'TURNER';
  v_text := 'an unemployed manager in text 3';
  update emptest set text3 = v_text where ename = 'JONES';
  commit;
end;
/

declare
  v_clob clob;
begin
  -- Set a field to an absurdly long value, with the match value way beyond 32k.
  update emptest set text1 = empty_clob() where ename = 'SMITH' returning text1 into v_clob;
  for i in 1..10000 loop
    dbms_lob.writeappend(v_clob, 36, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890');
  end loop;
  dbms_lob.writeappend(v_clob, 18, 'unemployed manager');
  commit;
end;
/

select empno, ename, clob_name, clob_value, length(clob_value) clob_length
  from emptest unpivot (clob_value for clob_name in (text1, text2, text3))
 where clob_value like '%unemployed%'
/

其结果将是:

EMPNO ENAME   CLOB_NAME CLOB_VALUE  CLOB_LENGTH
----- ------- --------- ----------- -----------
7566  JONES   TEXT3     <excluded>  31
7369  SMITH   TEXT1     <excluded>  360018
7369  SMITH   TEXT2     <excluded>  26012
7844  TURNER  TEXT1     <excluded>  32

最重要的是Oracle在处理LIKE的{​​{1}}时如何处理TEXT1关键字:请注意,该列的长度大于36万个字符。 我们尝试与SMITH数据类型一起使用的许多标准语法只有在Oracle将CLOB强制转换为CLOB时才起作用,但这具有固有的长度限制。

此测试表明,VARCHAR2比较确实适用于胖LIKE值-至少在我测试过的Oracle 12c中。

如果您尝试显示匹配的实际内容,情况将有所不同:如果需要,您需要熟悉CLOB软件包及其子程序,例如DBMS_LOBDBMS_LOB.INSTR您正在处理长DBMS_LOB.SUBSTR值。

相关问题