如何在T-SQL中匹配US-ASCII字符?

时间:2012-05-25 10:56:35

标签: tsql ascii sql-like

我想在一个列中存储网址。根据{{​​3}},US-ASCII是组成URL的字符集。

SQL Server具有VARCHAR类型,可以编码US-ASCII字符集中的所有字符,还有128个依赖于代码页的字符。

我想使用CHECK约束来确保列中的值仅包含US-ASCII字符集中的可打印字符;换句话说,ASCII(@char) >= 32 AND ASCII(@char) < 127表示字符串中的每个字符。

我认为我可以使用LIKE表达式在检查约束中执行此操作,但我找不到正确的模式。我正在尝试调整Itzik Ben-Gan在匹配允许范围之外的任何角色的技巧,他在文章RFC 3986中提到了这一点。

在我的测试工具中,我创建了一个候选表@TestData,用于插入我的列,一个用于LIKE运算符的模式表@Patterns,然后我选择匹配每个的结果针对每位候选人的模式:

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表达式中的模式有什么问题?

1 个答案:

答案 0 :(得分:3)

正如问题评论和similar question的答案中所建议的那样,我需要使用二进制整理条款。

如果我将select语句更改为:

SELECT
  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS ID,
  String,
  Pattern,
  CASE WHEN String NOT LIKE Pattern COLLATE Latin1_General_BIN THEN 1 ELSE 0 END AS [Match]
FROM @TestData CROSS JOIN @Patterns;

我得到以下结果集:

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                                                      %[^ -~]%     1
 8    http://www.google.com/                                   %[^ -~]%     1
 9    http://www.example.com/düsseldorf?neighbourhood=Lörick   %[^ -~]%     0
 10   1234                                                     %[^ -~]%     1

现在列匹配包含预期值。