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 / 问题 / 196570
Accepted
Shiva
Shiva
Asked: 2018-01-31 01:15:53 +0800 CST2018-01-31 01:15:53 +0800 CST 2018-01-31 01:15:53 +0800 CST

为什么 varchar 数据类型允许 unicode 值?

  • 772

我有一个带有 varchar 列的表。它允许商标(™)、版权(©)和其他 Unicode 字符,如下所示。

Create table VarcharUnicodeCheck
(
col1 varchar(100)
)

insert into VarcharUnicodeCheck (col1) values ('MyCompany')
insert into VarcharUnicodeCheck (col1) values ('MyCompany™')
insert into VarcharUnicodeCheck (col1) values ('MyCompany░')
insert into VarcharUnicodeCheck (col1) values ('MyCompanyï')
insert into VarcharUnicodeCheck (col1) values ('MyCompany')

select * from VarcharUnicodeCheck

但是varchar 的定义说,它允许非 unicode 字符串数据。但是 Trademark(™) 和 Registered(®) 符号是Unicode字符。定义是否与 varchar 数据类型的属性相矛盾?我读了几个链接,比如第一个和第二个。但是当定义说它只允许非 unicode 字符串值时,我仍然不明白为什么它允许 unicode 字符串。

sql-server datatypes
  • 5 5 个回答
  • 17450 Views

5 个回答

  • Voted
  1. Best Answer
    sepupic
    2018-01-31T02:07:41+08:002018-01-31T02:07:41+08:00

    但是 Trademark(™) 和 Registered(®) 符号是 Unicode 字符。

    你在这里错了。您的字符串仅包含 ascii 字符。

    这是一个简单的测试,显示您的字符都是 ascii(+ 一些扩展 ascii,ascii 代码在 128 到 255 之间):

    declare @VarcharUnicodeCheck table
    (
    col1 varchar(100)
    )
    
    insert into @VarcharUnicodeCheck (col1) values ('MyCompany')
    insert into @VarcharUnicodeCheck (col1) values ('MyCompany™')
    insert into @VarcharUnicodeCheck (col1) values ('MyCompany░')
    insert into @VarcharUnicodeCheck (col1) values ('MyCompanyï')
    insert into @VarcharUnicodeCheck (col1) values ('MyCompany')
    
    select *,
            right(col1, 1)as last_char, 
            ascii(right(col1, 1)) as_last_char_ascii
    from @VarcharUnicodeCheck;
    

    在这里您可以清楚地看到您的所有字符都是 1 字节编码的:

    在此处输入图像描述

    是的,它们不是纯 ascii 字符,但它们是Extended ASCII。

    在这里,我向您展示真正的 Unicode 字符Trademark(™)及其代码和二进制表示:

    declare @t table (uni_ch nchar(1), ascii_ch char(1));
    insert into @t values (N'™', '™');
    
    select unicode(uni_ch) as [unicode of ™], 
           ascii(ascii_ch) [ascii of ™], 
           cast(uni_ch as varbinary(10)) as [uni_ch as varbinary], 
           cast(ascii_ch as varbinary(10)) as [ascii_ch as varbinary]
    from @t;
    

    在此处输入图像描述

    最后,您可以看到 Trademark(™) Unicode 字符的代码是 8482 而不是 153:

    select nchar(8482), nchar(153)
    
    • 14
  2. Dan Guzman
    2018-01-31T05:03:19+08:002018-01-31T05:03:19+08:00

    从评论中,我同意“扩展 ASCII”是一个非常糟糕的术语,它实际上意味着一个代码页,它映射了 128-255 范围内的字符/代码点,超出了 ASCII 定义的标准 0-127 代码点范围。

    SQL Server 通过排序规则支持许多代码页。只要底层排序规则支持该字符,非 ASCII 字符就可以存储在 varchar 中。

    当 SQL Server 排序规则代码页为 1250 或更大时,“™”字符可以存储在 varchar/char 列中。下面的查询将列出这些:

    SELECT COLLATIONPROPERTY(name, 'CodePage') AS code_page, name, description
    FROM sys.fn_helpcollations()
    WHERE COLLATIONPROPERTY(name, 'CodePage') >= 1250
    ORDER BY name;
    

    但其中只有一个子集也支持“©”字符,因此列排序规则需要是以下之一以支持两者:

    SELECT COLLATIONPROPERTY(name, 'CodePage') AS code_page, name, description
    FROM sys.fn_helpcollations()
    WHERE COLLATIONPROPERTY(name, 'CodePage') IN(
        1250
        ,1251
        ,1252
        ,1253
        ,1254
        ,1255
        ,1256
        ,1257
        ,1258
    )
    ORDER BY name;
    
    • 7
  3. Solomon Rutzky
    2018-01-31T14:55:52+08:002018-01-31T14:55:52+08:00

    但是 varchar 的定义说,它允许非 unicode 字符串数据。但是 Trademark(™) 和 Registered(®) 符号是 Unicode字符。定义是否与 varchar 数据类型的属性相矛盾?

    虽然其他答案并不正确,但我认为指出基本术语的混淆会有所帮助。我在上面引用的问题中强调了两个词,作为这种混淆的一个例子。当 SQL Server 文档谈到 Unicode 和非 Unicode数据时,它们并不是在谈论字符。他们说的是代表某些字符的字节序列。NCHARUnicode 类型( 、NVARCHAR、XML和不推荐使用的 / evil NTEXT)和非 Unicode 类型(CHAR、VARCHAR和不推荐使用的 / evil TEXT)之间的主要区别在于它们可以存储的字节序列类型。

    非 Unicode 类型存储几个 8 位编码之一,而 Unicode 类型存储一个 16 位 Unicode 编码:UTF-16 Little Endian。正如其他答案所提到的,哪些字符可以以 8 位/非 Unicode 编码存储取决于代码页,该代码页由排序规则确定。虽然其他人已经注意到“字符”的字节值可以在它所在的代码页中变化,但在处理几个 EBCDIC 代码页之一时,字节值甚至可以在同一代码页内变化(Windows- 1252),仅在较旧的 SQL Server 排序规则(即名称以 开头的排序规则SQL_)中不应该使用。

    因此,定义是准确的:您可以设法以非 Unicode 类型存储的任何字符始终是 8 位的(即使它们将两个 8 位值组合为单个“字符”,这就是 Double-字节字符集/DBCS 代码页允许)。并且 Unicode 数据类型始终是 16 位的,即使它们有时将两个 16 位值组合用作单个“字符”(即,代理对又代表补充字符)。

    并且,由于 SQL Server 本身支持 SQL Server 2019 的 UTF-8 编码VARCHAR和CHAR数据类型,

    VARCHAR不能再被称为“非Unicode”。因此,从 2018 年 9 月 SQL Server 2019 的第一个公开测试版开始,我们应该将其VARCHAR称为“8 位数据类型”,即使是在 SQL Server 2019 之前的版本方面。这个术语适用于所有 4 种类型可用于的编码VARCHAR:

    1. 扩展的 ASCII
    2. 双字节字符集 (DBCS)
    3. EBCDIC
    4. UTF-8 (Unicode)

    只有TEXT数据类型(自 SQL Server 2005 起已弃用,因此不要使用它)是“非 Unicode”,但这只是技术性问题,将其称为“8 位数据类型”是准确的。

    NVARCHAR, NCHAR, 并且NTEXT可以称为“UTF-16”或“16 位数据类型”。我相信,Oracle 使用“仅限 Unicode”的术语NVARCHAR,但这并不能明确排除使用 UTF-8(也是 Unicode 编码)的可能性,因为它不起作用,所以最好坚持使用前两个选项。

    有关新的 UTF-8 编码的详细信息,请参阅我的帖子:

    SQL Server 2019 中的原生 UTF-8 支持:救世主还是假先知?

    PS 我正在慢慢地更新 SQL Server 文档以反映这些变化。

    PPS Microsoft 已经使用 UTF-8 信息更新了一些页面,包括问题中引用的char 和 varchar文档。它不再包含短语“non-Unicode”。但这只是一个仅供参考;它不会改变问题,因为这是关于非 Unicode 编码,其中包含被错误地认为是仅 Unicode 的字符。

    • 5
  4. IMSoP
    2018-01-31T11:41:31+08:002018-01-31T11:41:31+08:00

    这个问题包含一个关于 Unicode 是什么的核心误解。Unicode 字符集及其编码(如 UTF-8 和 UTF-16)是在计算机中表示文本的多种方式之一,其目的是取代所有其他字符集和编码。如果“非 Unicode 数据”的意思是“Unicode 中不存在的字符”,那么我在这个答案中使用的所有文本都不能存储在该类型中,因为拉丁字母的所有字母和日常英语中使用的常见标点符号都是包含在 Unicode 中。

    文本表示可以大致分为两部分:将不同字符(字母、数字、符号等)映射到参考图表上的数字的字符集;以及将这些数字表示为位模式的编码(在磁盘上、通过网络连接等)。在这里,我们主要关注第一部分:特定字符集的图表中列出了哪些字符。

    由于 Unicode 旨在为世界上的每个字符提供数字(它称为“代码点”),因此像 Wikipedia 这样的参考资料通常会将字符的 Unicode 位置作为参考信息的标准片段。但是,这并不意味着其他字符集也没有相同字符的映射。

    仍在使用的最古老和最简单的字符集(和编码)之一是 ASCII,它具有 128 个不同字符(0 到 127)的映射,因为它使用 7 位来编码每个字符。由于这排除了许多重音字符和常见符号,因此后来的编码使用 8 位,并映射相同的前 128 个字符,通过填充位置 128 到 255 添加到字符集。其中值得注意的是标准ISO 8859-1和ISO 8859- 15和 Microsoft 特定的Windows 代码页 1252。

    因此,回到 MS SQL Server:存储在 、 或 列中的“Unicode 字符串”nchar可以nvarchar表示ntext映射到 Unicode 字符集中的所有字符,因为它使用 Unicode 编码来存储数据。char存储在、varchar或列中的“非 Unicode 字符串”text只能表示以其他编码映射的字符。您可以存储在非 Unicode 列中的任何内容也可以存储在 Unicode 列中,但反之则不然。

    要确切知道可以存储哪些字符,您需要知道使用中的“排序规则”,它规定了 Microsoft 所称的“代码页”,如Microsoft 参考页中所述。在您的情况下,您可能正在使用我之前提到的非常常见的代码页 1252。

    您提到的字符同时存在于 Unicode 和 Code Page 1252 中:

    • Trademark(™) 出现在 Unicode 中的第 8482 位,在 CP1252 中的第 153 位
    • Registered(®) 恰好出现在 Unicode 和 CP1252 中的第 174 位
    • 3
  5. Kyle Rondeau
    2021-05-21T20:50:13+08:002021-05-21T20:50:13+08:00

    接受某事和只接受某事不是一回事。如果你去一个说“我们接受 50 美元的钞票”的得来速餐厅,这是否意味着他们只接受 50 美元的钞票?当然不是。同样,接受 Unicode 和只接受 Unicode 也不相同。您添加了“仅”一词,根据您的问题,它在您引用的定义中不存在。

    • -1

相关问题

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

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

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

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

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

Sidebar

Stats

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

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

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

    • 3 个回答
  • Marko Smith

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

    • 3 个回答
  • Marko Smith

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

    • 4 个回答
  • 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
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • 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
    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