带有模式匹配的 WHERE 子句以查找包含不在列表中的任何字符的行

GWR*_*GWR 4 sql-server-2008 sql-server

我在 SQL Server 2008 环境中。

我试图在WHERE子句中使用模式匹配来查找特定列的值包含非字母数字、下划线、破折号、句点或空格字符的行。

这是我的代码和示例数据,但我没有得到预期的结果。

在示例数据中,我想返回第 7、8、9 和 12 行,但我得到的是第 5 行和第 6 行。

如果这不是实现目标的最佳方式,我愿意听取其他方法。

我不在可以实现正则表达式的环境中,因此我的解决方案仅限于开箱即用的功能。

CREATE TABLE PATTERN_TEST
(
ID INT NOT NULL,
STRING NVARCHAR(40) NOT NULL
)

INSERT INTO PATTERN_TEST
SELECT 1, 'string' UNION 
SELECT 2, 'STRING' UNION 
SELECT 3, 'string space' UNION 
SELECT 4, 'STRING SPACE' UNION 
SELECT 5, 'string-dash' UNION 
SELECT 6, 'string-dash space' UNION 
SELECT 7, 'string "otherchar"' UNION 
SELECT 8, 'string "other char"' UNION 
SELECT 9, '"string"' UNION 
SELECT 10, 'string_underscore' UNION 
SELECT 11, 'string_underscore space' UNION
SELECT 12, '"'
;

SELECT * FROM PATTERN_TEST WHERE STRING LIKE '%[^a-zA-Z0-9_ -.]%';
Run Code Online (Sandbox Code Playgroud)

ype*_*eᵀᴹ 9

这也将起作用:

SELECT * 
FROM PATTERN_TEST 
WHERE STRING LIKE '%[^a-zA-Z0-9_ .-]%' ;
Run Code Online (Sandbox Code Playgroud)

reextester.com 上测试

唯一的区别是破折号 ( -) 放在[...]模式的末尾。它与破折号字符的特殊含义有关(A-Z被解释为“从AZ”的任何字符)。

在您的模式中,最后三个字符 (space-dash-dot: -.) 被解释为“从空格 ( ) 到点 ( .) 的任何字符”,结果不是想要/预期的。

你也可以逃避破折号:

WHERE STRING LIKE '%[^a-zA-Z0-9_ $-.]%' ESCAPE '$' ;
Run Code Online (Sandbox Code Playgroud)

请注意,使用ESCAPE 可能会对基数估计产生不利影响

有关详细信息,请参阅 MSDN 文档LIKE

如果 LIKE 模式中的转义字符后没有字符,则该模式无效并且 LIKE 返回 FALSE。如果转义字符后面的字符不是通配符,则丢弃转义字符,转义后面的字符被视为模式中的常规字符。这包括百分号 (%)、下划线 (_) 和左方括号 ([) 通配符,当它们包含在双括号 ([ ]) 中时。此外,在双括号字符 ([ ]) 中,可以使用转义字符,并且可以对插入符号 (^)、连字符 (-)和右括号 (])进行转义。

需要明确的是:特殊字符在用作非特殊字符时需要转义。在 [] 里面,三个 (^, -, ]) 是特殊的。把破折号放在最后更像是一个黑客。