在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中。


当前回答

在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数据库。

其他回答

另一个解决方案,应该适用于任何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)

内部选择可以用另一个模式源替换,比如表(或视图),如下所示:

WHERE EXISTS (SELECT 1
                FROM table_of_patterns t
               WHERE something LIKE t.pattern)

Table_of_patterns应该至少包含一个列模式,可以像这样填充:

INSERT INTO table_of_patterns(pattern) VALUES ('bla%');
INSERT INTO table_of_patterns(pattern) VALUES ('%foo%');
INSERT INTO table_of_patterns(pattern) VALUES ('batz%');

这适用于逗号分隔的值

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的组合进行了测试,它是这种问题的有效解决方案。试试下面的查询:

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

在T-SQL中,这个选项是有效的,但不是很快:

CREATE FUNCTION FN_LIKE_IN (@PROC NVARCHAR(MAX), @ITENS NVARCHAR(MAX)) RETURNS NVARCHAR(MAX) AS BEGIN
    
        --Search an item with LIKE inside a list delimited by "," Vathaire 11/06/2019
    
    DECLARE @ITEM NVARCHAR(MAX)
    WHILE CHARINDEX(',', @ITENS) > 0 BEGIN
        SET @ITEM = LEFT(@ITENS, CHARINDEX(',', @ITENS) - 1)
        --IF @ITEM LIKE @PROC
        IF @PROC LIKE @ITEM
            RETURN @PROC --@ITEM --1
        ELSE
            SET @ITENS = STUFF(@ITENS, 1, LEN(@ITEM) + 1, '')
    END
    IF @PROC LIKE @ITENS RETURN @PROC --@ITEM --1
    RETURN NULL --0
END

查询:

SELECT * FROM SYS.PROCEDURES
WHERE DBO.FN_LIKE_IN(NAME, 'PRC%,SP%') IS NOT NULL

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

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