【发布时间】:2012-05-31 23:09:13
【问题描述】:
我想将 URL 存储在一个列中。根据RFC 3986,US-ASCII 是构成 URL 的字符集。
SQL Server 具有 VARCHAR 类型,它可以编码来自 US-ASCII 字符集的所有字符,以及另外 128 个依赖于代码页的字符。
我想使用 CHECK 约束来确保列中的值仅包含 US-ASCII 字符集中的可打印字符;换句话说,ASCII(@char) >= 32 AND ASCII(@char) < 127 代表字符串中的每个字符。
我想我可以在检查约束中使用 LIKE 表达式来执行此操作,但我找不到正确的模式。我正在尝试改编 Itzik Ben-Gan 匹配允许范围之外的任何字符的技巧,他在他的文章 Can I convert this string to an integer? 中提出了这一点。
在我的测试工具中,我创建了一个表 @TestData 的候选表以插入到我的列中,一个表 @Patterns 的模式要与 LIKE 运算符一起使用,然后我选择将每个模式与每个候选者进行匹配的结果:
DECLARE @TestData TABLE (
String VARCHAR(60) COLLATE Latin1_General_CI_AS NOT NULL
);
INSERT INTO @TestData(String)
VALUES
('€ÿ'),
('ab3'),
('http://www.google.com/'),
('http://www.example.com/düsseldorf?neighbourhood=Lörick'),
('1234');
DECLARE @Patterns TABLE (
Pattern VARCHAR(12) COLLATE Latin1_General_CI_AS NOT NULL
);
INSERT INTO @Patterns (Pattern)
VALUES
('%[^0-9]%'),
('%[^' + CHAR(32) + '-' + CHAR(126) + ']%');
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS ID,
String,
Pattern,
CASE WHEN String NOT LIKE Pattern THEN 1 ELSE 0 END AS [Match]
FROM @TestData CROSS JOIN @Patterns;
插入@Patterns 的第一行类似于Itzik 用来匹配非数字字符的模式。第二行是我尝试将其用于可打印的 US-ASCII 字符范围之外的字符。
当我执行上述批处理时,我收到以下结果集:
ID String Pattern Match
--- -------------------------------------------------------- ------------ ------
1 €ÿ %[^0-9]% 0
2 ab3 %[^0-9]% 0
3 http://www.google.com/ %[^0-9]% 0
4 http://www.example.com/düsseldorf?neighbourhood=Lörick %[^0-9]% 0
5 1234 %[^0-9]% 1
6 €ÿ %[^ -~]% 0
7 ab3 %[^ -~]% 0
8 http://www.google.com/ %[^ -~]% 0
9 http://www.example.com/düsseldorf?neighbourhood=Lörick %[^ -~]% 0
10 1234 %[^ -~]% 0
正如预期的那样,第 5 行是匹配的,因为候选只包含数字。第 1 行到第 4 行中的候选不只包含数字,所以不要匹配模式。
正如预期的那样,第 6 行中的候选与模式不匹配,因为它包含“高 ASCII”字符。
我希望第 7、8 和 10 行中的候选项能够匹配,因为它们仅包含可打印的 US-ASCII 字符。但这些不匹配。
LIKE 表达式中的模式有什么问题?
【问题讨论】:
-
您需要使用二进制整理子句。模式语法中的范围基于排序规则。
-
不是重复的;情况不同。但是解决方法是一样的!