AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 34730
Accepted
Iain Samuel McLean Elder
Iain Samuel McLean Elder
Asked: 2013-02-15 03:37:12 +0800 CST2013-02-15 03:37:12 +0800 CST 2013-02-15 03:37:12 +0800 CST

为什么非数字 LIKE [0-9]?

  • 772

我的服务器的默认排序规则是 Latin1_General_CI_AS,由以下查询确定:

SELECT SERVERPROPERTY('Collation') AS Collation;

我惊讶地发现,通过这种排序规则,我可以使用 predicate 匹配字符串中的非数字字符LIKE '[0-9]'。

为什么在默认排序规则中会发生这种情况?我想不出这会有用的情况。我知道我可以使用二进制排序规则来解决该行为,但实现默认排序规则似乎是一种奇怪的方式。

过滤数字产生非数字字符

我可以通过创建一个包含所有可能的单字节字符值的列并使用数字匹配谓词过滤这些值来演示该行为。

下面的语句创建一个有 256 行的临时表,一个用于当前代码页中的每个代码点:

WITH P0(_) AS (SELECT 0 UNION ALL SELECT 0),
P1(_) AS (SELECT 0 FROM P0 AS L CROSS JOIN P0 AS R),
P2(_) AS (SELECT 0 FROM P1 AS L CROSS JOIN P1 AS R),
P3(_) AS (SELECT 0 FROM P2 AS L CROSS JOIN P2 AS R),
Tally(Number) AS (
  SELECT -1 + ROW_NUMBER() OVER (ORDER BY (SELECT 0))
  FROM P3
)
SELECT Number AS CodePoint, CHAR(Number) AS Symbol
INTO #CodePage
FROM Tally
WHERE Number >= 0 AND Number <= 255;

每行包含代码点的整数值和代码点的字符值。并非所有字符值都是可显示的 - 一些代码点是严格控制字符。这是输出的选择性样本SELECT CodePoint, Symbol FROM #CodePage:

0   
1   
2   
...
32   
33  !
34  "
35  #
...
48  0
49  1
50  2
...
65  A
66  B
67  C
...
253 ý
254 þ
255 ÿ

我希望能够过滤符号列以使用 LIKE 谓词并指定字符范围“0”到“9”来查找数字字符:

SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]';

它产生了令人惊讶的输出:

CodePoint   Symbol
48  0
49  1
50  2
51  3
52  4
53  5
54  6
55  7
56  8
57  9
178 ²
179 ³
185 ¹
188 ¼
189 ½
190 ¾

代码点 48 到 57 的集合是我所期望的。令我惊讶的是,上标和分数的符号也包含在结果集中!

将指数和分数视为数字可能有数学上的原因,但称它们为数字似乎是错误的。

使用二进制排序规则作为解决方法

我知道要获得我期望的结果,我可以强制执行相应的二进制排序规则 Latin1_General_BIN:

SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]' COLLATE Latin1_General_BIN;

结果集仅包括代码点 48 到 57:

CodePoint   Symbol
48  0
49  1
50  2
51  3
52  4
53  5
54  6
55  7
56  8
57  9
sql-server collation
  • 2 2 个回答
  • 19696 Views

2 个回答

  • Voted
  1. Best Answer
    Martin Smith
    2013-02-15T03:46:34+08:002013-02-15T03:46:34+08:00

    [0-9]不是某种定义为仅匹配数字的正则表达式。

    模式中的任何范围都LIKE根据排序规则匹配开始和结束字符之间的字符。

    SELECT CodePoint,
           Symbol,
           RANK() OVER (ORDER BY Symbol COLLATE Latin1_General_CI_AS) AS Rnk
    FROM   #CodePage
    WHERE  Symbol LIKE '[0-9]' COLLATE Latin1_General_CI_AS
    ORDER  BY Symbol COLLATE Latin1_General_CI_AS 
    

    退货

    CodePoint            Symbol Rnk
    -------------------- ------ --------------------
    48                   0      1
    188                  ¼      2
    189                  ½      3
    190                  ¾      4
    185                  ¹      5
    49                   1      5
    50                   2      7
    178                  ²      7
    179                  ³      9
    51                   3      9
    52                   4      11
    53                   5      12
    54                   6      13
    55                   7      14
    56                   8      15
    57                   9      16
    

    因此,您会得到这些结果,因为在您的默认排序规则下,这些字符排序在 之后0但之前9。

    看起来好像排序规则被定义为实际上以数学顺序对它们进行排序,分数在0和之间以正确的顺序排列1。

    您也可以使用集合而不是范围。为避免2匹配²,您需要一个CS排序规则

    SELECT CodePoint, Symbol
    FROM #CodePage
    WHERE Symbol LIKE '[0123456789]' COLLATE Latin1_General_CS_AS
    
    • 23
  2. Remus Rusanu
    2013-02-15T04:01:49+08:002013-02-15T04:01:49+08:00

    Latin1 是代码页 1252,其中178 是 'SUPERSCRIPT TWO'。这是一个Unicode上标:是把字符“2”当作上标。根据Unicode Technical Standard #10,它应该比较等于 2,请参阅8.1 Collat​​ion Folding:

    将兼容性(第三级)等效项(例如全角和上标字符)映射到代表性字符

    如果上标 2 与 2 比较不同,错误将是!在您说“但我的列不是 Unicode”之前,请放心:根据MSDN(请参阅 Windows 排序规则),所有字符串比较和排序都是根据 Unicode 规则完成的,即使磁盘上的表示是 CHAR。

    至于您示例中的其他字符,likeVULGAR FRACTION ONE QUARTER和 like,它们比较不等于任何数字,但是,正如 Mark 已经表明的那样,它们确实在 0 和 9 之间正确排序。

    当然,如果您更改代码页,您会得到不同的结果。例如。使用Greek_CS_AS(代码页 1253),您将获得代码为 178、179 和 189 的字符。

    • 6

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    授予用户对所有表的访问权限

    • 5 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve