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

sel*_*oup 322 sql t-sql sql-server oracle plsql

在SQL中(遗憾的是)LIKE由于数据库违反了几乎所有规范化规则,因此经常不得不使用" "条件.我现在无法改变它.但这与这个问题无关.

此外,我经常使用条件,例如WHERE something in (1,1,2,3,5,8,13,21)更好的可读性和SQL语句的灵活性.

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

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

WHERE something LIKE 'bla%'
OR something LIKE '%foo%'
OR something LIKE 'batz%'
Run Code Online (Sandbox Code Playgroud)

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

OMG*_*ies 185

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
Run Code Online (Sandbox Code Playgroud)

SQL Server:

WHERE CONTAINS(t.something, '"bla*" OR "foo*" OR "batz*"')
Run Code Online (Sandbox Code Playgroud)

参考:

  • 使用SQL Server(至少是2008版本)@Pilooz的注释也适用,您需要构建全文索引. (17认同)
  • 嗨,使用Oracle,您需要在要应用"CONTAINS"运算符的列上构建纯文本索引.根据您的数据量,这可能会很长. (11认同)

Rob*_*ijk 57

如果您想使您的语句易于阅读,那么您可以使用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.
Run Code Online (Sandbox Code Playgroud)

原始语法:

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.
Run Code Online (Sandbox Code Playgroud)

使用REGEXP_LIKE进行简单查看

SQL> select something
  2    from mytable
  3   where regexp_like (something,'^bla|foo|^batz')
  4  /

SOMETH
------
blabla
ofooof
batzzz

3 rows selected.
Run Code Online (Sandbox Code Playgroud)

但......

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

  • 真正.但正则表达式像疯了一样烧掉CPU,而不是I/O. 如果情况更糟,情况更糟,取决于表达式列表的大小以及列是否已编入索引等.这只是一个警告,因此原始海报在开始实施时并不会感到惊讶. (11认同)
  • 在10g中使用REGEXP的+1很好的例证.不过,我很好奇,如果表现真的会变得更糟.两者都需要全表和/或索引扫描,不是吗? (3认同)

KM.*_*KM. 48

你被困在了

WHERE something LIKE 'bla%'
OR something LIKE '%foo%'
OR something LIKE 'batz%'
Run Code Online (Sandbox Code Playgroud)

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

FROM YourTable                y
    INNER JOIN YourTempTable  t On y.something LIKE t.something
Run Code Online (Sandbox Code Playgroud)

尝试一下(使用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
Run Code Online (Sandbox Code Playgroud)

OUTPUT:

x
----------
abcdefg
abc

(2 row(s) affected)

x
----------
abc
abcdefg

(2 row(s) affected)
Run Code Online (Sandbox Code Playgroud)

  • 在SQL中,您可以获得索引使用和性能.仅对SQL可读性使用缩进和命名,当您为可读性进行其他修改时,您只会冒更改执行计划(这会影响索引使用和性能)的风险.如果您不小心,可以通过进行微不足道的更改,轻松地将即时运行的查询更改为非常慢的查询. (10认同)

Ben*_*oit 19

随着PostgreSQL的存在ANYALL形式:

WHERE col LIKE ANY( subselect )
Run Code Online (Sandbox Code Playgroud)

要么

WHERE col LIKE ALL( subselect )
Run Code Online (Sandbox Code Playgroud)

subselect只返回一列数据.


mik*_*mik 12

另一个解决方案应该适用于任何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)
Run Code Online (Sandbox Code Playgroud)

  • @Fandango68,但是选择的联合可以被另一个模式源替换,比如表、视图等。 (2认同)
  • @mik是的。没想到其他可能性。 (2认同)

Fam*_*erd 10

如果您想要封装上面显示的内部连接或临时表技术,我建议使用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.
Run Code Online (Sandbox Code Playgroud)

输出

1   Bass
2   Pike
7   Angler
8   Walleye


Ada*_*Dev 7

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

SELECT t.SomeField
FROM YourTable t
   JOIN #TempTableWithConditions c ON t.something LIKE c.ConditionValue
Run Code Online (Sandbox Code Playgroud)


A-K*_*A-K 7

改为使用内连接:

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
Run Code Online (Sandbox Code Playgroud)

  • @PhilFactor此解决方案可以创建重复的行. (3认同)

Mar*_*ark 6

从 2016 年开始,SQL Server 包含一个STRING_SPLIT 功能. 我正在使用 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
Run Code Online (Sandbox Code Playgroud)


Sim*_*lia 5

你甚至可以尝试这个

功能

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
Run Code Online (Sandbox Code Playgroud)

询问

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+'%';
Run Code Online (Sandbox Code Playgroud)


小智 5

我有一个简单的解决方案,至少在postgresql中有效,使用like any后跟正则表达式列表。这是一个示例,查看如何识别列表中的一些抗生素:

select *
from database.table
where lower(drug_name) like any ('{%cillin%,%cyclin%,%xacin%,%mycine%,%cephal%}')
Run Code Online (Sandbox Code Playgroud)


Luk*_*zda 5

我在这里使用SQl Server和Oracle,但是我很感兴趣是否可以在任何RDBMS中实现。

Teradata支持LIKE ALL/ANY语法:

列表中的所有字符串。
ANY 列表中的任何字符串。

?????????????????????????????????????????????????????????????????????
?      THIS expression …       ? IS equivalent to this expression … ?
?????????????????????????????????????????????????????????????????????
? x LIKE ALL ('A%','%B','%C%') ? x LIKE 'A%'                        ?
?                              ? AND x LIKE '%B'                    ?
?                              ? AND x LIKE '%C%'                   ?
?                              ?                                    ?
? x LIKE ANY ('A%','%B','%C%') ? x LIKE 'A%'                        ?
?                              ? OR x LIKE '%B'                     ?
?                              ? OR x LIKE '%C%'                    ?
?????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

编辑:

jOOQ版本3.12.0支持以下语法:

添加综合[NOT]像任何人和[NOT]像所有运算符

很多时候,SQL用户希望能够结合使用LIKE和IN谓词,例如:

SELECT *
FROM customer
WHERE last_name [ NOT ] LIKE ANY ('A%', 'E%') [ ESCAPE '!' ]
Run Code Online (Sandbox Code Playgroud)

解决方法是将谓词手动扩展为等效谓词

SELECT *
FROM customer
WHERE last_name LIKE 'A%'
OR last_name LIKE 'E%'
Run Code Online (Sandbox Code Playgroud)

jOOQ可以立即支持这种综合谓词。


Hum*_*bir 5

也许你认为这样的组合:

SELECT  * 
FROM    table t INNER JOIN
(
  SELECT * FROM (VALUES('bla'),('foo'),('batz')) AS list(col)
) l ON t.column  LIKE '%'+l.Col+'%'
Run Code Online (Sandbox Code Playgroud)

如果您已经为目标表定义了全文索引,那么您可以使用以下替代方案:

SELECT  * 
FROM    table t
WHERE CONTAINS(t.column, '"bla*" OR "foo*" OR "batz*"')
Run Code Online (Sandbox Code Playgroud)

  • 谢谢。IMO 这应该是公认的答案。并非每个人都有定义的全文索引(无论这意味着什么)您的第一个建议就像魅力一样。您甚至可以将通配符放入临时表值本身中,而不是在 LIKE 上连接。 (2认同)