在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%'
我正在使用SQl Server和Oracle,但我很感兴趣,如果可以在任何RDBMS中使用它。
答案 0 :(得分:174)
没有LIKE&组合在SQL中,在TSQL(SQL Server)或PLSQL(Oracle)中更少。部分原因是因为建议使用全文搜索(FTS)。
Oracle和SQL Server FTS实现都支持CONTAINS关键字,但语法仍然略有不同:
WHERE CONTAINS(t.something, 'bla OR foo OR batz', 1) > 0
WHERE CONTAINS(t.something, '"bla*" OR "foo*" OR "batz*"')
参考:
答案 1 :(得分:55)
如果您想使您的声明易于阅读,那么您可以使用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.
但......
由于表现不佳,我不会自己推荐。我坚持使用几个LIKE谓词。所以这些例子只是为了好玩。
答案 2 :(得分:43)
你坚持
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
输出:
x
----------
abcdefg
abc
(2 row(s) affected)
x
----------
abc
abcdefg
(2 row(s) affected)
答案 3 :(得分:18)
对于PostgreSQL,有ANY
or ALL
form:
WHERE col LIKE ANY( subselect )
或
WHERE col LIKE ALL( subselect )
其中subselect只返回一列数据。
答案 4 :(得分: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)
答案 5 :(得分:10)
如果您想要封装上面显示的Inner Join或temp表技术,我建议使用TableValue用户函数。这样可以让它读得更清楚。
中定义的拆分功能我们可以根据我创建的名为“Fish”的表(int id,varchar(50)名称)编写以下内容
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
答案 6 :(得分:7)
一种方法是将条件存储在临时表(或SQL Server中的表变量)中并加入到以下内容中:
SELECT t.SomeField
FROM YourTable t
JOIN #TempTableWithConditions c ON t.something LIKE c.ConditionValue
答案 7 :(得分: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
答案 8 :(得分:4)
功能
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+'%';
答案 9 :(得分:3)
我有一个简单的解决方案,至少使用 postgresql ,使用like any
后跟正则表达式列表。这是一个例子,看一下列表中的一些抗生素:
select *
from database.table
where lower(drug_name) like any ('{%cillin%,%cyclin%,%xacin%,%mycine%,%cephal%}')
答案 10 :(得分:3)
我也想知道这样的事情。我刚刚使用SUBSTRING
和IN
的组合进行了测试,它是解决此类问题的有效方法。请尝试以下查询:
Select * from TB_YOUR T1 Where SUBSTRING(T1.Something, 1,3) IN ('bla', 'foo', 'batz')
答案 11 :(得分:2)
For Sql Server you can resort to Dynamic SQL.
Most of the time in such situations you have the parameter of IN clause based on some data from database.
The example below is a little "forced", but this can match various real cases found in legacy databases.
Suppose you have table Persons where person names are stored in a single field PersonName as FirstName + ' ' + LastName. You need to select all persons from a list of first names, stored in field NameToSelect in table NamesToSelect, plus some additional criteria (like filtered on gender, birth date, etc)
You can do it as follows
-- @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
答案 12 :(得分:2)
我在这里使用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%' │ └──────────────────────────────┴────────────────────────────────────┘
答案 13 :(得分: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);
答案 14 :(得分:2)
我可能有这方面的解决方案,但据我所知,它只适用于SQL Server 2008。我发现你可以使用https://stackoverflow.com/a/7285095/894974中描述的行构造函数来使用like子句加入'虚构'表。 听起来比较复杂,看起来:
SELECT [name]
,[userID]
,[name]
,[town]
,[email]
FROM usr
join (values ('hotmail'),('gmail'),('live')) as myTable(myColumn) on email like '%'+myTable.myColumn+'%'
这将导致所有用户都拥有列表中提供的电子邮件地址。 希望它对任何人都有用。这个问题困扰了我一段时间。
答案 15 :(得分:1)
这适用于逗号分隔值
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%')
如果您希望它使用索引,则必须省略第一个'%'
字符。
答案 16 :(得分:1)
在Oracle RBDMS中,您可以使用REGEXP_LIKE函数实现此行为。
以下代码将测试列表表达式 one | two em> | 三个 | 四个 | 五个 (其中管道“ | ”符号表示或逻辑运算)。
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。
答案 17 :(得分:1)
如果你使用MySQL,你可以得到的最接近的是全文搜索:
答案 18 :(得分:0)
没有这样的答案:
public DataSource dataSourceSecond() throws SQLException {
HikariConfig config = new HikariConfig("D:/hikari2.properties");
在oracle没问题。
答案 19 :(得分:0)
从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
答案 20 :(得分:0)
在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%')
答案 21 :(得分:0)
也许您认为这样的组合:
SELECT *
FROM table t INNER JOIN
(
SELECT * FROM (VALUES('bla'),('foo'),('batz')) AS list(col)
) l ON t.column LIKE '%'+l.Col+'%'
如果您已为目标表定义了全文本索引,则可以使用以下替代方法:
SELECT *
FROM table t
WHERE CONTAINS(t.column, '"bla*" OR "foo*" OR "batz*"')
答案 22 :(得分:0)
我知道这已经很晚了,但是我也遇到了类似的情况。我需要一个“ Like In”运算符来存储一组存储过程,该存储过程接受许多参数,然后使用这些参数来聚合来自多个RDBMS系统的数据,因此没有RDBMS特定的技巧起作用,但是该存储过程和任何功能它将在MS SQL Server上运行,因此我们可以使用T-SQL来为每个RDBMS生成完整的SQL语句,但是输出必须与RDBMS完全无关。
这是我目前想出的将分隔字符串(例如存储过程中的参数)转换为SQL块的方法。我称其为“ Like IN”的“地衣”。懂吗?
Lichen.sql
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =======================================================================
-- Lichen - Scalar Valued Function
-- Returns nvarchar(512) of "LIKE IN" results. See further documentation.
-- CREATOR: Norman David Cooke
-- CREATED: 2020-02-05
-- UPDATED:
-- =======================================================================
CREATE OR ALTER FUNCTION Lichen
(
-- Add the parameters for the function here
@leadingAnd bit = 1,
@delimiter nchar(1) = ';',
@colIdentifier nvarchar(64),
@argString nvarchar(256)
)
RETURNS nvarchar(512)
AS
BEGIN
-- Declare the return variable here
DECLARE @result nvarchar(512)
-- set delimiter to detect (add more here to detect a delimiter if one isn't provided)
DECLARE @delimit nchar(1) = ';'
IF NOT @delimiter = @delimit
SET @delimit = @delimiter
-- check to see if we have any delimiters in the input pattern
IF CHARINDEX(@delimit, @argString) > 1 -- check for the like in delimiter
BEGIN -- begin 'like in' branch having found a delimiter
-- set up a table variable and string_split the provided pattern into it.
DECLARE @lichenTable TABLE ([id] [int] IDENTITY(1,1) NOT NULL, line NVARCHAR(32))
INSERT INTO @lichenTable SELECT * FROM STRING_SPLIT(@argString, ';')
-- setup loop iterators and determine how many rows were inserted into lichen table
DECLARE @loopCount int = 1
DECLARE @lineCount int
SELECT @lineCount = COUNT(*) from @lichenTable
-- select the temp table (to see whats inside for debug)
--select * from @lichenTable
-- BEGIN AND wrapper block for 'LIKE IN' if bit is set
IF @leadingAnd = 1
SET @result = ' AND ('
ELSE
SET @result = ' ('
-- loop through temp table to build multiple "LIKE 'x' OR" blocks inside the outer AND wrapper block
WHILE ((@loopCount IS NOT NULL) AND (@loopCount <= @lineCount))
BEGIN -- begin loop through @lichenTable
IF (@loopcount = 1) -- the first loop does not get the OR in front
SELECT @result = CONCAT(@result, ' ', @colIdentifier, ' LIKE ''', line, '''') FROM @lichenTable WHERE id = @loopCount
ELSE -- but all subsequent loops do
SELECT @result = CONCAT(@result, ' OR ', @colIdentifier, ' LIKE ''', line, '''') FROM @lichenTable WHERE id = @loopCount
SET @loopcount = @loopCount + 1 -- increment loop
END -- end loop through @lichenTable
-- set final parens after lichenTable loop
SET @result = CONCAT(@result, ' )')
END -- end 'like in' branch having found a delimiter
ELSE -- no delimiter was provided
BEGIN -- begin "no delimiter found" branch
IF @leadingAnd = 1
SET @result = CONCAT(' AND ', @colIdentifier, ' LIKE ''' + @argString + '''')
ELSE
SET @result = CONCAT(' ', @colIdentifier, ' LIKE ''' + @argString + '''')
END -- end "no delimiter found" branch
-- Return the result of the function
RETURN @result
END -- end lichen function
GO
可能已经计划了定界符检测,但是目前它默认为分号,因此您可以在其中放置default
。这可能有错误。 @leadingAnd
参数只是一个位值,用于确定是否要在块的前面放置“ AND”,以便与其他WHERE子句添加项很好地配合。
用法示例(在argString中带有定界符)
SELECT [dbo].[Lichen] (
default -- @leadingAND, bit, default: 1
,default -- @delimiter, nchar(1), default: ';'
,'foo.bar' -- @colIdentifier, nvarchar(64), this is the column identifier
,'01%;02%;%03%' -- @argString, nvarchar(256), this is the input string to parse "LIKE IN" from
)
GO
将返回包含以下内容的nvarchar(512):
AND ( foo.bar LIKE '01%' OR foo.bar LIKE '02%' OR foo.bar LIKE '%03%' )
如果输入不包含定界符,它将也跳过该块:
用法示例(在argString中没有定界符)
SELECT [dbo].[Lichen] (
default -- @leadingAND, bit, default: 1
,default -- @delimiter, nchar(1), default: ';'
,'foo.bar' -- @colIdentifier, nvarchar(64), this is the column identifier
,'01%' -- @argString, nvarchar(256), this is the input string to parse "LIKE IN" from
)
GO
将返回包含以下内容的nvarchar(512):
AND foo.bar LIKE '01%'
我将继续进行此工作,因此,如果我忽略了某些内容(显而易见或其他明显的内容),请随时发表评论或联系我们。
答案 23 :(得分:0)
很抱歉疏通旧帖子,但它有很多观点。我本周遇到了类似的问题,并提出了这种模式:
declare @example table ( sampletext varchar( 50 ) );
insert @example values
( 'The quick brown fox jumped over the lazy dog.' ),
( 'Ask not what your country can do for you.' ),
( 'Cupcakes are the new hotness.' );
declare @filter table ( searchtext varchar( 50 ) );
insert @filter values
( 'lazy' ),
( 'hotness' ),
( 'cupcakes' );
-- Expect to get rows 1 and 3, but no duplication from Cupcakes and Hotness
select *
from @example e
where exists ( select * from @filter f where e.sampletext like '%' + searchtext + '%' )
Exists()比IMO联接要好一些,因为它仅测试集合中的每个记录,但是如果有多个匹配项,则不会导致重复。
答案 24 :(得分:-3)
这样做
WHERE something + '%' in ('bla', 'foo', 'batz')
OR '%' + something + '%' in ('tra', 'la', 'la')
或
WHERE something + '%' in (select col from table where ....)