首页 文章

SQL中是否有“LIKE”和“IN”的组合?

提问于
浏览
275

在SQL中,我很遗憾地经常不得不使用“ LIKE ”条件,因为数据库几乎违反了每个规范化规则 . 我可以_1828057_与这个问题无关 .

此外,我经常使用像_1528058这样的条件来提高SQL语句的可读性和灵活性 .

在没有编写复杂的子选择的情况下,有没有可能将这两种方法结合起来?

我想要一些像 WHERE something LIKE ('bla%', '%foo%', 'batz%') 一样简单的东西而不是这个:

WHERE something LIKE 'bla%'
OR something LIKE '%foo%'
OR something LIKE 'batz%'

我在这里使用SQl Server和Oracle,但我很感兴趣,如果在任何RDBMS中都可以这样做 .

22 回答

  • 1

    SQL中没有LIKE和IN的组合,更不用说TSQL(SQL Server)或PLSQL(Oracle) . 部分原因是因为全文搜索(FTS)是推荐的替代方案 .

    Oracle和SQL Server FTS实现都支持CONTAINS关键字,但语法仍然略有不同:

    甲骨文:

    WHERE CONTAINS(t.something, 'bla OR foo OR batz', 1) > 0
    

    SQL Server:

    WHERE CONTAINS(t.something, '"bla*" OR "foo*" OR "batz*"')
    

    参考:

  • 7

    如果您想使您的语句易于阅读,那么您可以使用REGEXP_LIKE(从Oracle版本10开始) .

    示例表:

    SQL> create table mytable (something)
      2  as
      3  select 'blabla' from dual union all
      4  select 'notbla' from dual union all
      5  select 'ofooof' from dual union all
      6  select 'ofofof' from dual union all
      7  select 'batzzz' from dual
      8  /
    
    Table created.
    

    原始语法:

    SQL> select something
      2    from mytable
      3   where something like 'bla%'
      4      or something like '%foo%'
      5      or something like 'batz%'
      6  /
    
    SOMETH
    ------
    blabla
    ofooof
    batzzz
    
    3 rows selected.
    

    使用REGEXP_LIKE进行简单查看

    SQL> select something
      2    from mytable
      3   where regexp_like (something,'^bla|foo|^batz')
      4  /
    
    SOMETH
    ------
    blabla
    ofooof
    batzzz
    
    3 rows selected.
    

    BUT ...

    由于性能不佳,我不会自己推荐它 . 我坚持使用几个LIKE谓词 . 所以这些例子只是为了好玩 .

  • 7

    你被困在了

    WHERE something LIKE 'bla%'
    OR something LIKE '%foo%'
    OR something LIKE 'batz%'
    

    除非你填充临时表(包括带有数据的通配符)并加入如下:

    FROM YourTable                y
        INNER JOIN YourTempTable  t On y.something LIKE t.something
    

    尝试一下(使用SQL Server语法):

    declare @x table (x varchar(10))
    declare @y table (y varchar(10))
    
    insert @x values ('abcdefg')
    insert @x values ('abc')
    insert @x values ('mnop')
    
    insert @y values ('%abc%')
    insert @y values ('%b%')
    
    select distinct *
    FROM @x x
    WHERE x.x LIKE '%abc%' 
       or x.x LIKE '%b%'
    
    
    select distinct x.*  
    FROM @x             x
        INNER JOIN  @y  y On x.x LIKE y.y
    

    OUTPUT:

    x
    ----------
    abcdefg
    abc
    
    (2 row(s) affected)
    
    x
    ----------
    abc
    abcdefg
    
    (2 row(s) affected)
    
  • 3

    使用PostgreSQL有ANY or ALL form:

    WHERE col LIKE ANY( subselect )
    

    要么

    WHERE col LIKE ALL( subselect )
    

    subselect只返回一列数据 .

  • 55

    如果您想要封装上面显示的内部连接或临时表技术,我建议使用TableValue用户函数 . 这样可以让它读得更清楚一些 .

    使用在以下位置定义的拆分功能后:http://www.logiclabz.com/sql-server/split-function-in-sql-server-to-break-comma-separated-strings-into-table.aspx

    我们可以根据我创建的名为“Fish”的表(int id,varchar(50)Name)编写以下内容

    SELECT Fish.* from Fish 
        JOIN dbo.Split('%ass,%e%',',') as Splits 
        on Name like Splits.items  //items is the name of the output column from the split function.
    

    输出

    1   Bass
    2   Pike
    7   Angler
    8   Walleye
    
  • 166

    另一个解决方案应该适用于任何RDBMS:

    WHERE EXISTS (SELECT 1
                    FROM (SELECT 'bla%' pattern FROM dual UNION ALL
                          SELECT '%foo%'        FROM dual UNION ALL
                          SELECT 'batz%'        FROM dual)
                   WHERE something LIKE pattern)
    
  • 1

    一种方法是将条件存储在临时表(或SQL Server中的表变量)中并加入到这样的:

    SELECT t.SomeField
    FROM YourTable t
       JOIN #TempTableWithConditions c ON t.something LIKE c.ConditionValue
    
  • 2

    改为使用内连接:

    SELECT ...
    FROM SomeTable
    JOIN
    (SELECT 'bla%' AS Pattern 
    UNION ALL SELECT '%foo%'
    UNION ALL SELECT 'batz%'
    UNION ALL SELECT 'abc'
    ) AS Patterns
    ON SomeTable.SomeColumn LIKE Patterns.Pattern
    
  • 10

    你甚至可以试试这个

    功能

    CREATE  FUNCTION [dbo].[fn_Split](@text varchar(8000), @delimiter varchar(20))
    RETURNS @Strings TABLE
    (   
      position int IDENTITY PRIMARY KEY,
      value varchar(8000)  
    )
    AS
    BEGIN
    
    DECLARE @index int
    SET @index = -1
    
    WHILE (LEN(@text) > 0)
      BEGIN 
        SET @index = CHARINDEX(@delimiter , @text) 
        IF (@index = 0) AND (LEN(@text) > 0) 
          BEGIN  
            INSERT INTO @Strings VALUES (@text)
              BREAK 
          END 
        IF (@index > 1) 
          BEGIN  
            INSERT INTO @Strings VALUES (LEFT(@text, @index - 1))  
            SET @text = RIGHT(@text, (LEN(@text) - @index)) 
          END 
        ELSE
          SET @text = RIGHT(@text, (LEN(@text) - @index))
        END
      RETURN
    END
    

    询问

    select * from my_table inner join (select value from fn_split('ABC,MOP',','))
    as split_table on my_table.column_name like '%'+split_table.value+'%';
    
  • -3

    我也想知道这样的事情 . 我刚刚使用 SUBSTRINGIN 的组合进行了测试,它是解决此类问题的有效方法 . 请尝试以下查询:

    Select * from TB_YOUR T1 Where SUBSTRING(T1.Something, 1,3) IN ('bla', 'foo', 'batz')
    
  • 0

    我有一个简单的解决方案,至少在 postgresql 中工作,使用 like any 后跟正则表达式列表 . 这是一个例子,看一下列表中的一些抗生素:

    select *
    from database.table
    where lower(drug_name) like any ('{%cillin%,%cyclin%,%xacin%,%mycine%,%cephal%}')
    
  • 1

    对于Sql Server,您可以使用动态SQL .

    大多数情况下,在这种情况下,您可以根据数据库中的某些数据获得IN子句的参数 .

    下面的示例有点“强制”,但这可以匹配遗留数据库中的各种实际案例 .

    假设您有表 Persons ,其中人名存储在单个字段 PersonName 中作为FirstName ' ' LastName . 您需要从名字列表中选择所有人,存储在表 NamesToSelect 中的字段 NameToSelect 中,以及一些其他标准(例如按性别,出生日期等过滤)

    你可以这样做

    -- @gender is nchar(1), @birthDate is date 
    
    declare 
      @sql nvarchar(MAX),
      @subWhere nvarchar(MAX)
      @params nvarchar(MAX)
    
    -- prepare the where sub-clause to cover LIKE IN (...)
    -- it will actually generate where clause PersonName Like 'param1%' or PersonName Like 'param2%' or ...   
    set @subWhere = STUFF(
      (
        SELECT ' OR PersonName like ''' + [NameToSelect] + '%''' 
            FROM [NamesToSelect] t FOR XML PATH('')
      ), 1, 4, '')
    
    -- create the dynamic SQL
    set @sql ='select 
          PersonName
          ,Gender
          ,BirstDate    -- and other field here         
      from [Persons]
      where 
        Gender = @gender
        AND BirthDate = @birthDate
        AND (' + @subWhere + ')'
    
    set @params = ' @gender nchar(1),
      @birthDate Date'     
    
    EXECUTE sp_executesql @sql, @params,    
      @gender,  
      @birthDate
    
  • 8

    我可能有一个解决方案,虽然它只能在我知道的SQL Server 2008中工作 . 我发现您可以使用https://stackoverflow.com/a/7285095/894974中描述的行构造函数使用like子句加入'fictional'表 . 它听起来更复杂,看起来:

    SELECT [name]
      ,[userID]
      ,[name]
      ,[town]
      ,[email]
    FROM usr
    join (values ('hotmail'),('gmail'),('live')) as myTable(myColumn) on email like '%'+myTable.myColumn+'%'
    

    这将导致所有用户都拥有类似列表中提供的电子邮件地址 . 希望它对任何人都有用 . 这个问题困扰了我一段时间 .

  • 1

    我在这里使用SQl Server和Oracle,但我很感兴趣,如果在任何RDBMS中都可以这样做 .

    Teradata支持LIKE ALL/ANY语法:

    列表中的每个字符串 . 列表中的任何字符串 . ┌──────────────────────────────┬────────────────── ──────────────────┐
    │这个表达式......│等同于这个表达式......│
    ├──────────────────────────────┼────────────────── ──────────────────┤
    │xLIKE ALL('A%','%B','%C%')│xLIKE'A%'│
    ││ANDx LIKE'%B'│
    ││ANDx LIKE'%C%'│
    │││
    │xLIKE ANY('A%','%B','%C%')│xLIKE'A%'│
    ││或x喜欢'%B'│
    ││或x LIKE'%C%'│
    └──────────────────────────────┴────────────────── ──────────────────┘

  • 4

    如果你使用MySQL,你可以得到的最接近的是全文搜索:

    Full-Text Search, MySQL Documentation

  • 18

    这适用于逗号分隔值

    DECLARE @ARC_CHECKNUM VARCHAR(MAX)
    SET @ARC_CHECKNUM = 'ABC,135,MED,ASFSDFSF,AXX'
    SELECT ' AND (a.arc_checknum LIKE ''%' + REPLACE(@arc_checknum,',','%'' OR a.arc_checknum LIKE ''%') + '%'')''
    

    评估到:

    AND (a.arc_checknum LIKE '%ABC%' OR a.arc_checknum LIKE '%135%' OR a.arc_checknum LIKE '%MED%' OR a.arc_checknum LIKE '%ASFSDFSF%' OR a.arc_checknum LIKE '%AXX%')
    

    如果要使用索引,则必须省略第一个 '%' 字符 .

  • 2

    在Oracle中,您可以通过以下方式使用集合:

    WHERE EXISTS (SELECT 1
                    FROM TABLE(ku$_vcnt('bla%', '%foo%', 'batz%'))
                   WHERE something LIKE column_value)
    

    这里我使用了预定义的集合类型 ku$_vcnt ,但您可以像这样声明自己的集合类型:

    CREATE TYPE my_collection AS TABLE OF VARCHAR2(4000);
    
  • 3

    在Oracle RBDMS中,您可以使用REGEXP_LIKE函数实现此行为 .

    以下代码将测试字符串 three 是否存在于列表表达式 one|two|three|four|five 中(其中管道“ | ”符号表示OR逻辑运算) .

    SELECT 'Success !!!' result
    FROM dual
    WHERE REGEXP_LIKE('three', 'one|two|three|four|five');
    
    RESULT
    ---------------------------------
    Success !!!
    
    1 row selected.
    

    前面的表达式相当于:

    three=one OR three=two OR three=three OR three=four OR three=five
    

    所以它会成功 .

    另一方面,以下测试将失败 .

    SELECT 'Success !!!' result
    FROM dual
    WHERE REGEXP_LIKE('ten', 'one|two|three|four|five');
    
    no rows selected
    

    自10g版本以来,Oracle中有几个与正则表达式(REGEXP_ *)相关的函数 . 如果您是Oracle开发人员并且对此主题感兴趣,这应该是一个良好的开端Using Regular Expressions with Oracle Database .

  • 0

    没有这样的答案:

    SELECT * FROM table WHERE something LIKE ('bla% %foo% batz%')
    

    在oracle没问题 .

  • 43

    从2016年开始,SQL Server包含 STRING_SPLIT function . 我正在使用SQL Server v17.4,我让它为我工作:

    DECLARE @dashboard nvarchar(50)
    SET @dashboard = 'P1%,P7%'
    
    SELECT * from Project p
    JOIN STRING_SPLIT(@dashboard, ',') AS sp ON p.ProjectNumber LIKE sp.value
    
  • 1

    在Teradata中,您可以使用 LIKE ANY ('%ABC%','%PQR%','%XYZ%') . 下面是一个为我产生相同结果的例子

    --===========
    --  CHECK ONE
    --===========
    SELECT *
    FROM Random_Table A
    WHERE (Lower(A.TRAN_1_DSC) LIKE ('%american%express%centurion%bank%')
    OR Lower(A.TRAN_1_DSC) LIKE ('%bofi%federal%bank%')
    OR Lower(A.TRAN_1_DSC) LIKE ('%american%express%bank%fsb%'))
    
    ;
    --===========
    --  CHECK TWO
    --===========
    SELECT *
    FROM Random_Table  A
    WHERE Lower(A.TRAN_1_DSC) LIKE ANY 
    ('%american%express%centurion%bank%',
    '%bofi%federal%bank%',
    '%american%express%bank%fsb%')
    
  • 2

    做这个

    WHERE something + '%' in ('bla', 'foo', 'batz')
    OR '%' + something + '%' in ('tra', 'la', 'la')
    

    要么

    WHERE something + '%' in (select col from table where ....)
    

相关问题