在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中。
另一个解决方案,应该适用于任何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%');
在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中没有LIKE和IN的组合,更不用说TSQL (SQL Server)或PLSQL (Oracle)了。部分原因是全文检索(FTS)是推荐的替代方法。
Oracle和SQL Server的FTS实现都支持CONTAINS关键字,但语法仍然略有不同:
Oracle:
WHERE CONTAINS(t.something, 'bla OR foo OR batz', 1) > 0
SQL服务器:
WHERE CONTAINS(t.something, '"bla*" OR "foo*" OR "batz*"')
要查询的列必须是全文索引的。
参考:
使用Oracle文本构建全文搜索应用程序
理解SQL Server全文