【问题标题】:Combine LIKE and IN using only WHERE clause仅使用 WHERE 子句组合 LIKE 和 IN
【发布时间】:2016-05-21 09:25:09
【问题描述】:

我知道有人问过这个问题,但我的看法略有不同。我有一个用例,我唯一可以控制的是查询的 WHERE 子句,并且我有 2 个表。

使用简单的例子:

Table1 包含 1 个名为“FULLNAME”的列,其中包含数百个值
Table2 包含 1 个名为“PATTERN”的列,其中包含一些匹配的文本

所以,我需要做的是从表 1 中选择与表 2 中的值匹配的所有值。

这是一个简单的例子:

表 1(全名)
南极洲
安哥拉
澳大利亚
非洲
印度
印度尼西亚

表 2(模式)


实际上我需要的是表 1 中的条目,其中包含表 2 中的值(结果将是南极洲、安哥拉、印度、印度尼西亚)

换句话说,我需要的是这样的:

Select * from Table1 where FULLNAME IN LIKE (Select '%' || Pattern || '%' from 表2)

这里的棘手之处在于我只能控制 where 子句,我根本无法控制 Select 子句或添加连接,因为我使用的产品只允许控制 where 子句。我也不能使用存储过程。

这可能吗?

我使用 Oracle 作为后端数据库

谢谢

【问题讨论】:

  • 模式是否总是两个字符,您只想在开头(如您的示例中)或任何地方(如“包含”和您使用通配符所建议的那样)匹配?

标签: sql oracle where-in


【解决方案1】:

一种可能的方法是在子查询中结合使用EXISTSLIKE

select * from table1 t1 
where exists (select null 
              from table2 t2 
              where t1.fullname like '%' || t2.pattern || '%');

【讨论】:

    【解决方案2】:

    如果模式总是两个字符并且只需要匹配全名的开头,就像您展示的示例一样,您可以这样做:

    Select * from Table1 where substr(FULLNAME, 1, 2) IN (Select Pattern from Table2)
    

    这会阻止使用 Table1 上的任何索引,您的实际情况可能需要更加灵活...

    或者可能效率更低,类似于 TomH 的方法,但在子查询中加入

    Select * from Table1 where FULLNAME IN (
      Select t1.FULLNAME from Table1 t1
      Join Table2 t2 on t1.FULLNAME like '%'||t2.Pattern||'%')
    

    【讨论】:

      【解决方案3】:

      是的,这涉及到一些诡计。从概念上讲,我所做的是将 PATTERN 中的列转换为单个单元格,并将其与 REGEX_LIKE 一起使用

      所以“AN 和 IN”的值变成了一个单一的值 '(AN|IN)' - 我只是将它提供给 regexp_like

      SELECT FULLNAME from table1  where  
      regexp_like(FULLNAME,(SELECT '(' || SUBSTR (SYS_CONNECT_BY_PATH (FULLNAME  , '|'), 2) || ')' Table2
                FROM (SELECT FULLNAME , ROW_NUMBER () OVER (ORDER BY FULLNAME) rn,
                             COUNT (*) OVER () cnt
                        FROM Table2)
               WHERE rn = cnt START WITH rn = 1 CONNECT BY rn = PRIOR rn + 1))
      

      regexp_like 中的子查询将列转换为包含正则表达式字符串的单个单元格。

      虽然我确实意识到这可能是一个性能杀手,但幸运的是我现在并没有那么在意性能

      【讨论】:

      • 您使用的是什么版本的 Oracle?如果 11g 或更高,你可以使用LISTAGG() 而不是疯狂的SYS_CONNECT_BY_PATH()
      • 我在 11g 上,所以是的,你是对的,我将用 LISTAGG 替换它。谢谢
      【解决方案4】:

      我相信你可以通过一个简单的JOIN来做到这一点:

      SELECT DISTINCT
          fullname
      FROM
          Table1 T1
      INNER JOIN Table2 T2 ON T1.fullname LIKE '%' || T2.pattern || '%'
      

      DISTINCT 适用于您可能与Table2 中的多行匹配的情况。

      【讨论】:

      • 同意,但是我不能使用 JOIN,我必须只使用 where 子句来执行此操作...不过我已经想通了,很快就会发布答案
      猜你喜欢
      • 2018-03-08
      • 1970-01-01
      • 2011-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-03
      • 1970-01-01
      相关资源
      最近更新 更多