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

在SQL中(可悲的是)经常不得不使用“ LIKE ”条件,因为数据库几乎违反了每个规范化的规则。 我现在无法改变。 但这与问题无关。

此外,我经常使用WHERE something in (1,1,2,3,5,8,13,21)条件来提高我的SQL语句的可读性和灵活性。

有没有可能把这两件事情结合起来而不写复杂的子select?

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

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

我正在与SQl服务器和Oracle在这里工作,但我很感兴趣,如果这在任何RDBMS中都是可能的。

在SQL中没有LIKE&IN的组合,在TSQL(SQL Server)或PLSQL(Oracle)中没有。 部分原因是因为全文search(FTS)是推荐的select。

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*"') 

参考:

  • 使用Oracle文本构build全文search应用程序
  • 了解SQL Server全文

如果您想使您的语句易于阅读,则可以使用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. 

但是…

由于不太好的performance,我不会自己推荐它。 我会坚持几个LIKE谓词。 所以这些例子只是为了好玩。

你坚持了

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

除非你填充一个临时表(包括数据中的通配符)并join,如下所示:

 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 @xx WHERE xx LIKE '%abc%' or xx LIKE '%b%' select distinct x.* FROM @xx INNER JOIN @yy On xx LIKE yy 

OUTPUT:

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

使用PostgreSQL有ANYALLforms:

 WHERE col LIKE ANY( subselect ) 

要么

 WHERE col LIKE ALL( subselect ) 

子查询只返回一列数据。

我会build议使用TableValue用户函数,如果你想封装上面显示的内部联接或临时表技术。 这将使其更清楚地阅读。

使用以下url中定义的分割函数之后: http : //www.logiclabz.com/sql-server/split-function-in-sql-server-to-break-comma-separated-strings-into-table.aspx

我们可以根据我创build的名为“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低音
 2派克
 7钓鱼者
 8 Walleye

一种方法是将条件存储在临时表(或SQL Server中的表variables)中,并join到如下所示:

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

使用内部连接代替:

 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 

你甚至可以试试这个

function

 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+'%'; 

另一个解决scheme,应该在任何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) 

对于Sql Server,您可以使用dynamicSQL。

大多数情况下,在这种情况下,基于来自数据库的某些数据,您有IN子句的参数。

下面的例子有点“强制”,但是这可以匹配遗留数据库中发现的各种真实案例。

假设你有人员姓名存储在单个字段PersonName作为名字+''+姓氏。 您需要从名字列表中select所有人,存储在名称select表中的字段名称中,再加上一些额外的条件(比如根据性别,出生date等进行过滤)

你可以这样做,如下所示

 -- @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 

我可能有一个解决scheme,但据我所知,它只能在SQL Server 2008中工作。 我发现您可以使用https://stackoverflow.com/a/7285095/894974中描述的行构造函数使用类似子句来join“虚构”表。; 这听起来更复杂,看起来:

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

这将导致所有使用电子邮件地址的用户像列表中提供的那样。 希望这对任何人都有用。 问题一直困扰着我。

如果您使用的是MySQL,则可以获得最接近的全文search:

全文search,MySQL文档

这适用于逗号分隔值

 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%') 

如果您希望使用索引,则必须省略第一个'%'字符。

我也想知道这样的事情。 我只是使用SUBSTRINGIN的组合进行testing,对于这类问题是一个有效的解决scheme。 尝试下面的查询:

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

Oracle中,您可以按照以下方式使用集合:

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

在这里我使用了预定义的集合typesku$_vcnt ,但是你可以像这样声明自己的types:

 CREATE TYPE my_collection AS TABLE OF VARCHAR2(4000); 

我有一个简单的解决scheme,至less在postgresql中使用, like any其次正则expression式的列表。 下面是一个例子,看看在列表中确定一些抗生素:

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

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

以下代码将testingstring3是否出现在列表expression式one |中 两个 | | | | (其中pipe道“ | ”符号表示OR逻辑运算)。

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

先前的expression相当于:

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

所以它会成功。

另一方面,下面的testing将会失败。

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

从10g版本开始,在Oracle中有几个与正则expression式(REGEXP_ *)相关的函数。 如果您是Oracle开发人员并且对此主题感兴趣,那么在Oracle数据库中使用正则expression式应该是一个很好的开始。

做这个

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

要么

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