在SQL I中(很遗憾)经常不得不使用“LIKE”条件,因为数据库违反了几乎所有的规范化规则。我现在改变不了。但这与问题无关。

此外,我经常使用诸如WHERE(1,1,2,3,5,8,13,21)中的某些内容之类的条件,以提高SQL语句的可读性和灵活性。

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

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

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

我在这里与SQl Server和Oracle一起工作,但我感兴趣的是,这是否可能在任何RDBMS中。


当前回答

这样做

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

or

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

其他回答

很抱歉挖出了一个旧帖子,但它有很多观点。这周我遇到了一个类似的问题,我想到了这个模式:

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()比join()工作得稍微好一点,因为它只测试集合中的每个记录,但如果有多个匹配则不会导致重复。

您可以以牺牲性能为代价,为大量元素动态地执行此操作,但这是可行的。

DECLARE @val nvarchar(256),
@list nvarchar(max) = 'one,two,three,ten,five';
CREATE table #table  (FIRST_NAME nvarchar(512), LAST_NAME nvarchar(512));
CREATE table #student  (FIRST_NAME nvarchar(512), LAST_NAME nvarchar(512), EMAIL 
nvarchar(512));
INSERT INTO #student (FIRST_NAME, LAST_NAME, EMAIL)
SELECT 'TEST', ' redOne' ,'test.redOne@toto.com' UNION ALL
SELECT 'student', ' student' ,'student@toto.com' UNION ALL
SELECT 'student', ' two' ,'student.two@toto.com' UNION ALL
SELECT 'hello', ' ONE TWO THREE' ,'student.two@toto.com'

DECLARE check_cursor CURSOR FOR select value from STRING_SPLIT(@list,',')

OPEN check_cursor  
FETCH NEXT FROM check_cursor INTO @val
WHILE @@FETCH_STATUS = 0  
    BEGIN
     PRINT @val
       IF EXISTS (select * from #student where REPLACE(FIRST_NAME, ' ','') 
like '%' + @val + '%' OR REPLACE(LAST_NAME, ' ','') like '%' + @val + '%') 
       BEGIN
       INSERT INTO #table (FIRST_NAME, LAST_NAME )
       SELECT TOP 1 FIRST_NAME, LAST_NAME VALUE from #student where 
REPLACE(FIRST_NAME, ' ','') like '%' + @val + '%' OR REPLACE(LAST_NAME, ' ','') 
like '%' + @val + '%'
       END;

      FETCH NEXT FROM check_cursor INTO @val 
    END
CLOSE check_cursor;  
DEALLOCATE check_cursor;  

SELECT * FROM #table;
DROP TABLE #table;
DROP TABLE #student;

这样做

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

or

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

我可能有一个解决方案,虽然它将只工作在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+'%' 

这将导致所有用户的电子邮件地址与列表中提供的相同。 希望对大家有用。这个问题困扰了我一段时间。

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

下面的代码将测试字符串3是否出现在列表表达式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开发人员,对这个主题感兴趣,这应该是一个很好的开始使用正则表达式与Oracle数据库。