在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有ANY
或ALL
forms:
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%')
如果您希望使用索引,则必须省略第一个'%'
字符。
我也想知道这样的事情。 我只是使用SUBSTRING
和IN
的组合进行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 ....)