什么时候必须在SQL Server中使用NVARCHAR/NCHAR而不是VARCHAR/CHAR?

Pet*_*der 65 sql-server unicode nvarchar collation

我们必须使用Unicode类型时是否有规则?

我已经看到大多数欧洲语言(德语,意大利语,英语......)在VARCHAR列中的同一数据库中都很好.

我正在寻找类似的东西:

  1. 如果你有中文 - >使用NVARCHAR
  2. 如果你有德语和阿拉伯语 - >使用NVARCHAR

那么服务器/数据库的整理呢?

我不想像这里建议的一样使用NVARCHAR.varchar 和nvarchar SQL Server数据类型之间的主要性能差异是什么?

Cad*_*oux 110

您想要使用NVARCHAR的真正原因是当您在同一列中使用不同的语言时,您需要在不解码的情况下在T-SQL中寻址列,您希望能够在SSMS中"本地"查看数据,或者您想要标准化Unicode.

如果将数据库视为哑存储,则完全可以在VARCHAR中存储宽字符串和不同(甚至可变长度)的编码(例如UTF-8).当您尝试编码和解码时会出现问题,特别是如果不同行的代码页不同.这也意味着SQL Server将无法轻松处理数据,以便在(可能是可变的)编码列上查询T-SQL.

使用NVARCHAR可以避免这一切.

我建议NVARCHAR用于任何具有用户输入数据的列,该列相对不受约束.

我建议将VARCHAR用于任何自然键列(如车牌,SSN,序列号,服务标签,订单号,机场呼号等),这些列通常由标准或法规或惯例定义和约束.用户输入的VARCHAR,非常有限(如电话号码)或代码(ACTIVE/CLOSED,Y/N,M/F,M/S/D/W等).绝对没有理由使用NVARCHAR.

所以对于一个简单的规则:

VARCHAR保证受限制NVARCHAR否则

  • 应该注意的是,*"不同的语言"*并不仅仅意味着不同的行可以包含来自不同语言的值.它还意味着数据库的默认排序规则(即服务器计算机的语言环境)与任何客户端计算机的语言环境不同.例如,服务器机器设置为"en-US",但我的PC设置为"fr-US". (4认同)
  • 许多亚洲国家(包括中国)在其牌照中使用了标识符,因此,除非您100%确定您的程序绝对不会并且永远不会处理此类数据,否则最好将nvarchar用于车牌.是的,这包括交通违规者登记,停车场和车辆运输方法等.来自中国的人完全有可能乘坐渡轮甚至开车到你的国家,并将车停在你的车库里. (3认同)
  • >>当你在同一列中有不同的语言时....就是这样! (2认同)

Vit*_*tox 16

两个最高票的答案都是错误的。它应该与“存储不同/多种语言”无关。您可以支持西班牙语ñ和英语等字符,只需使用公共varchar字段和Latin1_General_CI_AS COLLATION,例如

短版
,您应该使用NVARCHAR/NCHAR无论何时ENCODING,这是确定COLLATION的领域,不支持所需要的字符。
此外,根据 SQL Server 版本,您可以使用 specific COLLATIONs,例如Latin1_General_100_CI_AS_SC_UTF8自 SQL Server 2019 以来可用的。 在VARCHAR字段(或整个表/数据库)上设置此排序规则,将UTF-8 ENCODING用于存储和处理该字段上的数据,允许完全支持UNICODE字符,因此它包含的任何语言。


要充分认识到:
要完全明白我做一下解释,这是强制性的,以拥有的概念UNICODEENCODINGCOLLATION在你的脑袋都非常清楚了。如果你不这样做,那么首先看看下面我关于“什么是 UNICODE、编码、排序和 UTF-8,以及它们是如何相关的”部分和提供的文档链接的谦逊和简化的解释。此外,我在这里所说的一切都特定于Microsoft SQL Server,以及它如何在char/ncharvarchar/nvarchar字段中存储和处理数据。

假设我们想在我们的 MSSQL Server 数据库中存储一个特殊的文本。它可能是一条 Instagram 评论,如“我喜欢 stackoverflow!”。
即使是 ASCII 也可以完美支持纯英文部分,但是由于还有一个 emoji,它是UNICODE标准中指定的字符,我们需要一个ENCODING支持这个 Unicode 字符的字符。

MSSQL Server使用COLLATION,以确定哪些ENCODING是在使用char/ nchar/ varchar/nvarchar场。因此,与很多人想象的不同,COLLATION 不仅是关于数据的排序和比较,而且是关于ENCODING,因此:我们的数据将如何存储!

那么,我们如何知道我们的整理使用的编码是什么?有了这个:

SELECT COLLATIONPROPERTY( 'Latin1_General_CI_AI' , 'CodePage' ) AS [CodePage]
--returns 1252
Run Code Online (Sandbox Code Playgroud)

这个简单的 SQL 返回Windows Code Pagefor a COLLATION。AWindows Code Page只不过是到 的另一个映射ENCODINGs。对于Latin1_General_CI_AI COLLATION它返回的Windows Code Page代码1252,映射到Windows-1252 ENCODING.
因此,对于具有 的varchar列,Latin1_General_CI_AI COLLATION此字段将使用 处理其数据Windows-1252 ENCODING,并且仅正确存储此编码支持的字符。

如果我们检查Windows-1252Windows-1252 ENCODING规范字符列表,我们会发现这种编码不支持我们的表情符号字符。如果我们仍然尝试一下:

包含 UNICODE 字符的文本,由于我们对 varchar 字段的整理和编码而被错误地存储

好的,那么我们如何解决这个问题??实际上,这取决于,这很好!

NCHAR/NVARCHAR

在 SQL Server 2019 之前,我们只有NCHARNVARCHAR字段。有人说它们是UNICODE田地。那是错的!. 同样,这取决于字段COLLATION和 SQLServer 版本。微软的“nchar and nvarchar (Transact-SQL)”文档完美地说明了:

从 SQL Server 2012 (11.x) 开始,当使用支持补充字符 (SC) 的排序规则时,这些数据类型存储完整范围的 Unicode 字符数据并使用 UTF-16 字符编码。如果指定了非 SC 归类,则这些数据类型仅存储 UCS-2 字符编码支持的字符数据子集。

换句话说,如果我们使用早于 2012 年的 SQL Server,例如 SQL Server 2008 R2,ENCODING对于那些字段将使用UCS-2 ENCODING支持UNICODE. 但是,如果我们使用 SQL Server 2012 或更新版本,并定义一个COLLATIONSupplementary Character启用的,那么我们的字段将使用UTF-16 ENCODING完全支持UNICODE.


但是,还有更多!我们现在可以使用 UTF-8 了!!

CHAR/VARCHAR

从 SQL Server 2019 开始,我们可以使用CHAR/VARCHAR字段并且仍然完全支持UNICODE使用UTF-8 ENCODING!!!

来自 Microsoft 的“char 和 varchar (Transact-SQL)”文档

从 SQL Server 2019 (15.x) 开始,当使用启用 UTF-8 的排序规则时,这些数据类型会存储完整范围的 Unicode 字符数据并使用 UTF-8 字符编码。如果指定了非 UTF-8 归类,则这些数据类型仅存储该归类的相应代码页支持的字符子集。

再次,换句话说,如果我们使用 2019 年之前的 SQL Server,例如 SQL Server 2008 R2,我们需要检查ENCODING使用之前解释的方法。但是,如果我们使用 SQL Server 2019 或更新版本,并定义一个COLLATIONlike Latin1_General_100_CI_AS_SC_UTF8,那么我们的字段将使用UTF-8 ENCODING它是迄今为止最常用和最有效的支持所有UNICODE字符的编码。


奖金信息:

关于 OP 对“我已经看到大多数欧洲语言(德语、意大利语、英语等)在 VARCHAR 列中的同一数据库中都很好”的观察,我认为很高兴知道为什么会这样:

对于最常见的COLLATIONs,如默认的 asLatin1_General_CI_AISQL_Latin1_General_CP1_CI_ASthe ENCODINGwill be Windows-1252for varcharfields。如果我们查看它的文档,我们可以看到它支持:

英语、爱尔兰语、意大利语、挪威语、葡萄牙语、西班牙语、瑞典语。此外还有德语、芬兰语和法语。和荷兰语除外?特点

但正如我之前所说的,这与语言无关,而是关于您希望支持/存储哪些字符,如表情符号示例中所示,或者诸如“锂电池的电阻为 0.5?”之类的句子。我们再次使用简单的英语和希腊字母/字符“omega”(这是电阻的符号,以欧姆为单位),Windows-1252 ENCODING.

结论:

所以,它来了!当使用char/ncharvarchar/nvarchar取决于字符要支持,这也是您的SQL服务器,将确定的版本COLLATIONs,因此ENCODINGs您有可用。




什么是 UNICODE、ENCODING、COLLATION 和 UTF-8,以及它们之间的关系
注意:以下所有解释都是简化。请参阅提供的文档链接以了解有关这些概念的所有详细信息。

  • UNICODE- 是一种标准,一种约定,旨在规范统一组织表中的所有字符。在这个表中,每个字符都有一个唯一的编号。这个数字通常称为字符的code point.
    Unicode 不是编码!

  • ENCODING- 是字符和字节/字节序列之间的映射。因此,编码用于将字符“转换”为字节,反之亦然,从字节到字符。其中最流行的是UTF-8ISO-8859-1Windows-1252ASCII。你可以把它想象成一个“转换表”(我在这里真的简化了)。

  • COLLATION- 那个很重要。即使是微软的文档也没有像它应该的那样清楚地说明这一点。排序规则指定您的数据将如何排序、比较和存储!. 是的,我敢打赌你不会期待最后一个,对吧!?在归类SQL Server决定过这将是ENCODING用在特定char/ nchar/ varchar/nvarchar场。

  • ASCII ENCODING- 是最早的编码之一。它既是字符表(就像 的一个自己的小版本UNICODE)及其字节映射。所以它不会将一个字节映射到UNICODE,而是将一个字节映射到它自己的字符表。此外,它始终只使用 7 位,并支持 128 个不同的字符。它足以支持所有大小写的英文字母、数字、标点符号和其他一些有限数量的字符。ASCII 的问题在于,由于它只使用了 7 位,而且当时几乎每台计算机都是 8 位,因此还有另外 128 种字符的可能性需要“探索”,每个人都开始将这个“可用”字节映射到自己的字符表,创造了很多不同ENCODINGs

  • UTF-8 ENCODING- 这是另一个ENCODING,使用最多(如果不是最多的话)ENCODING。它使用可变字节宽度(根据规范,一个字符的长度可以是 1 到 6 个字节)并且完全支持所有UNICODE字符。

  • Windows-1252 ENCODING- 也是最常用的一种ENCODING,它在 SQL Server 上被广泛使用。它是固定大小的,所以每个字符总是 1 个字节。它还支持来自各种语言的许多口音,但不支持所有现有的,也不支持UNICODE. 这就是为什么您的varchar字段具有像Latin1_General_CI_AS支持á, é,ñ字符这样的通用排序规则,即使它不使用支持UNICODE ENCODING.

资源:
https : //blog.greglow.com/2019/07/25/sql-think-that-varchar-characters-if-so-think-again/
https://medium.com/@apiltamang/unicode-utf -8-and-ascii-encodings-made-easy-5bfbe3a1c45a
https://www.johndcook.com/blog/2019/09/09/how-utf-8-works/
https://www.w3.org/ International/questions/qa-what-is-encoding

https://en.wikipedia.org/wiki/List_of_Unicode_characters
https://www.fileformat.info/info/charset/windows-1252/list.htm

https://docs .microsoft.com/en-us/sql/t-sql/data-types/char-and-varchar-transact-sql?view=sql-server-ver15
https://docs.microsoft.com/en-us/ sql/t-sql/data-types/nchar-and-nvarchar-transact-sql?view=sql-server-ver15
https://docs.microsoft.com/en-us/sql/t-sql/statements/windows-collat​​ion-name-transact-sql?view=sql-server-ver15
https://docs.microsoft.com/en -us/sql/t-sql/statements/sql-server-collat​​ion-name-transact-sql?view=sql-server-ver15
https://docs.microsoft.com/en-us/sql/relational-databases/ collat​​ions/collat​​ion-and-unicode-support?view=sql-server-ver15#SQL-collat​​ions

SQL Server 默认字符编码
https://en.wikipedia.org/wiki/Windows_code_page


Jos*_*rke 10

您必须在任何时候存储多种语言时使用NVARCHAR.我相信你必须将它用于亚洲语言,但不要引用我.

如果您以俄语为例并将其存储在varchar中,这就是问题,只要您定义了正确的代码页,就可以了.但是,假设你使用默认的英文sql install,那么俄语字符将无法正确处理.如果您使用的是NVARCHAR(),则可以正确处理它们.

编辑

好的,让我引用MSDN,也许我是特定的,但你不想在varcar列中存储多个代码页,而你可以不应该

处理存储在char,varchar,varchar(max)或文本数据类型中的文本数据时,要考虑的最重要的限制是系统只能验证来自单个代码页的信息.(您可以存储来自多个代码页的数据,但不建议这样做.)用于验证和存储数据的确切代码页取决于列的排序规则.如果尚未定义列级排序规则,则使用数据库的排序规则.要确定用于给定列的代码页,可以使用COLLATIONPROPERTY函数,如以下代码示例所示:

这里还有一些:

此示例说明了许多语言环境(例如Georgian和Hindi)没有代码页,因为它们是仅限Unicode的排序规则.这些排序规则不适用于使用char,varchar或text数据类型的列

所以格鲁吉亚语或印地语真的需要存储为nvarchar.阿拉伯语也是一个问题:

您可能遇到的另一个问题是,当您希望支持的所有字符都不包含在代码页中时,无法存储数据.在许多情况下,Windows将特定代码页视为"最适合"的代码页,这意味着无法保证您可以依赖代码页来处理所有文本; 它只是最好的一个.这方面的一个例子是阿拉伯语脚本:它支持各种语言,包括Baluchi,Berber,Farsi,Kashmiri,Kazakh,Kirghiz,Pashto,Sindhi,Uighur,Urdu等.所有这些语言都有除Windows代码页1256中定义的阿拉伯语之外的其他字符.如果您尝试将这些额外字符存储在具有阿拉伯语排序规则的非Unicode列中,

使用Unicode时要记住一些事项,尽管您可以在单个列中存储不同的语言,但只能使用单个排序规则进行排序.有些语言使用拉丁字符,但不像其他拉丁语言那样排序.口音是一个很好的例子,我不能记住这个例子,但是有一种东欧语言,其Y不像英语Y那样.然后有西班牙语用户在西班牙语用户出口后排序.

总而言之,在处理内部化时,您必须处理所有问题.我认为从一开始就更容易使用Unicode字符,避免额外的转换并占用空间.因此我先前的发言.

  • >>任何时候你必须使用NVARCHAR存储多种语言这是不正确的.德语,意大利语和英语与VARCHAR列相同.请更具体一点 (3认同)

che*_*vim 5

希腊语需要在 N 列类型上使用 UTF-8: \xce\xb1\xce\xb2\xce\xb3 ;)

\n