我们必须使用Unicode类型时是否有规则?
我已经看到大多数欧洲语言(德语,意大利语,英语,......)在VARCHAR列中的同一数据库中都很好。
我正在寻找类似的东西:
服务器/数据库的整理怎么样?
我不想像这里建议的那样使用NVARCHAR What are the main performance differences between varchar and nvarchar SQL Server data types?
答案 0 :(得分:108)
您想要使用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否则
答案 1 :(得分:10)
您必须在任何时候存储多种语言时使用NVARCHAR。我相信你必须将它用于亚洲语言,但不要引用我。
如果您以俄语为例并将其存储在varchar中,则会出现问题,只要您定义了正确的代码页,就可以了。但是,假设你使用默认的英文sql install,那么俄语字符将无法正确处理。如果您使用的是NVARCHAR(),则可以正确处理它们。
好吧,让我引用MSDN,也许我是特定的,但你不想在varcar列中存储多个代码页,而你可以不应该
处理文本数据时 存储在char,varchar中, varchar(max)或文本数据类型 最重要的考虑因素 只是来自单一的信息 代码页可以通过验证 系统。 (您可以存储来自的数据 多个代码页,但事实并非如此 推荐。)使用的确切代码页 验证和存储数据取决于 关于列的整理。如果一个 列级排序规则尚未完成 定义,数据库的整理 用来。确定代码页 用于给定列的,你 可以使用COLLATIONPROPERTY 功能,如下所示 代码示例:
还有一些:
这个例子说明了这个事实 许多语言环境,例如格鲁吉亚语和 印地语,没有代码页,因为他们 是仅限Unicode的排序规则。那些 整理不适合 使用char,varchar或的列 文本数据类型
所以格鲁吉亚语或印地语真的需要存储为nvarchar。阿拉伯语也是一个问题:
您可能遇到的另一个问题是 没有时无法存储数据 所有你想要的角色 支持包含在代码中 页。在很多情况下,Windows会考虑 一个特定的代码页是“最好的 适合“代码页,这意味着有 不能保证你可以依赖 用于处理所有文本的代码页;它是 只是最好的一个。一个 这方面的例子是阿拉伯语脚本: 它支持多种语言, 包括俾路支,柏柏尔人,波斯人, 克什米尔,哈萨克斯坦,吉尔吉斯,普什图语, 信德,维吾尔,乌尔都语等。所有的 这些语言有额外的 超出阿拉伯语的字符 Windows代码中定义的语言 第1256页。如果您尝试存储 这些额外的角色 具有阿拉伯语的非Unicode列 整理,人物是 转换成问号。
使用Unicode时要记住一些事项,尽管您可以在一个列中存储不同的语言,但只能使用单个排序规则进行排序。有些语言使用拉丁字符,但不像其他拉丁语言那样排序。口音是一个很好的例子,我不能记住这个例子,但是有一种东欧语言,其Y不像英语Y那样。然后有西班牙语ch,西班牙语用户将在h之后进行排序。< / p>
总而言之,在处理内部化时,您必须处理所有问题。我认为从一开始就更容易使用Unicode字符,避免额外的转换并占用空间。因此,我先前的发言。
答案 2 :(得分:5)
两个最受欢迎的答案都是错误的。它应该与“存储不同/多种语言”无关。您可以支持ñ
和英语之类的西班牙语字符,只需使用常见的varchar
字段和Latin1_General_CI_AS
COLLATION
,例如
简短版本
每当由字段NVARCHAR
确定的NCHAR
不支持所需的字符时,应使用ENCODING
/ COLLATION
。
另外,根据SQL Server版本的不同,您可以使用特定的COLLATIONs
,例如Latin1_General_100_CI_AS_SC_UTF8
,自SQL Server 2019起可用。在VARCHAR
字段(或整个表/数据库)上设置此排序规则),将使用UTF-8
ENCODING
来存储和处理该字段上的数据,从而完全支持UNICODE
字符,并因此支持它所包含的任何语言。
完全了解:
要完全理解我要解释的内容,必须将UNICODE
,ENCODING
和COLLATION
的概念弄清楚。如果您不这样做,那么首先请看下面关于“什么是UNICODE,编码,集合和UTF-8,以及它们之间的关系”的简明扼要的解释以及随附的文档链接。另外,我在这里所说的一切都是特定于Microsoft SQL Server
的,以及它如何存储和处理char
/ nchar
和varchar
/ nvarchar
字段中的数据。
假设我们要在我们的MSSQL Server数据库中存储一个特殊的文本。可能是Instagram评论为“我喜欢stackoverflow!?”。
即使是ASCII码,也可以完美地支持普通英语部分,但是由于还有一个表情符号,它是UNICODE
标准中指定的字符,因此我们需要一个ENCODING
支持此Unicode字符。
MSSQL Server使用COLLATION
来确定ENCODING
/ char
/ nchar
/ varchar
字段上使用的nvarchar
。因此,与很多人不同的是,COLLATION
不仅与数据的排序和比较有关,而且与ENCODING
有关,因此:我们的数据将如何已存储!
所以,我们如何知道我们的编码所使用的编码是什么?与此有关:
SELECT COLLATIONPROPERTY( 'Latin1_General_CI_AI' , 'CodePage' ) AS [CodePage]
--returns 1252
此简单的SQL返回Windows Code Page
的{{1}}。 COLLATION
就是对Windows Code Page
的另一个映射。对于ENCODINGs
Latin1_General_CI_AI
,它返回COLLATION
代码Windows Code Page
,该代码映射到1252
Windows-1252
。
因此,对于带有ENCODING
varchar
的{{1}}列,此字段将使用Latin1_General_CI_AI
COLLATION
处理其数据,并且仅正确存储此字段支持的字符编码。
如果我们检查Windows-1252
规范Character List for Windows-1252,我们会发现此编码不支持我们的表情符号字符。如果我们仍然尝试:
好,那我们该如何解决呢?实际上,这取决于情况,那就好!
ENCODING
/ Windows-1252 ENCODING
在SQL Server 2019之前,我们只有NCHAR
和NVARCHAR
字段。有人说它们是NCHAR
字段。 那是错误的!。同样,它取决于字段的NVARCHAR
以及SQLServer版本。
微软的"nchar and nvarchar (Transact-SQL)" documentation完美地指定了:
从SQL Server 2012(11.x)开始,当 使用启用了补充字符(SC)的排序规则,这些数据 类型存储所有Unicode字符数据,并使用 UTF-16字符编码。如果指定了非SC归类,则 这些数据类型仅存储受支持的字符数据的子集 UCS-2字符编码。
换句话说,如果我们使用早于2012年的SQL Server,例如SQL Server 2008 R2,则这些字段的UNICODE
将使用COLLATION
,它支持ENCODING
的子集。但是,如果我们使用SQL Server 2012或更高版本,并定义一个启用了UCS-2 ENCODING
的{{1}},则在我们的字段中将使用UNICODE
COLLATION
,它完全支持{{ 1}}。
还有,还有更多!我们现在可以使用UTF-8了!
Supplementary Character
/ UTF-16
从SQL Server 2019开始,我们可以使用ENCODING
/ UNICODE
字段,并且仍使用CHAR
{{1}来完全支持VARCHAR
} !!!
来自微软的"char and varchar (Transact-SQL)" documentation:
从SQL Server 2019(15.x)开始,当 使用启用了UTF-8的排序规则,这些数据类型存储整个范围 Unicode字符数据,并使用UTF-8字符编码。如果一个 如果指定非UTF-8归类,则这些数据类型仅存储 该字符的相应代码页支持的字符子集 整理。
同样,换句话说,如果我们使用早于2019年的SQL Server,例如SQL Server 2008 R2,则需要使用前面说明的方法检查CHAR
。但是,如果我们使用SQL Server 2019或更高版本,并定义一个VARCHAR
之类的UNICODE
,则我们的字段将使用UTF-8
ENCODING
,这是迄今为止使用最广泛,效率最高的编码支持所有ENCODING
个字符。
奖励信息:
关于OP对的观察,“我发现大多数欧洲语言(德语,意大利语,英语,...)在VARCHAR列的同一数据库中都可以使用” ,我认为这是很高兴知道为什么会这样:
对于最常见的COLLATION
,例如默认值Latin1_General_100_CI_AS_SC_UTF8
或UTF-8
,ENCODING
对于UNICODE
字段将是COLLATIONs
。如果我们看看它的documentation,我们可以看到它支持:
英语,爱尔兰语,意大利语,挪威语,葡萄牙语,西班牙语,瑞典语。加 还有德语,芬兰语和法语。还有荷兰语,除了IJ字符
但是正如我之前说的,这与语言无关,与表情符号示例中所示的期望/支持的字符有关,或诸如“锂电池的电阻为0.5Ω”之类的句子,其中我们再次使用了简单的英语和希腊字母/字符“ omega”(以欧姆为单位的电阻符号),Latin1_General_CI_AI
SQL_Latin1_General_CP1_CI_AS
无法正确处理。
结论:
就这样!使用ENCODING
/ Windows-1252
和varchar
/ Windows-1252
的时间取决于您要支持的字符,以及将决定哪个{{1 }},因此还有ENCODING
可用。
什么是UNICODE,CODEC,COLLATION和UTF-8,以及它们之间的关系
注意:以下所有说明均为简化。请参阅提供的文档链接以了解有关这些概念的所有详细信息。
char
-是一种标准,一种约定,旨在规范统一和有组织的表格中的所有字符。在此表中,每个字符都有一个唯一的数字。此数字通常称为字符的nchar
。
UNICODE不是编码!
varchar
-是字符和字节序列之间的映射。因此,使用编码将字符“转换”为字节,反之亦然,从字节转换为字符。其中最受欢迎的是nvarchar
,COLLATIONs
,ENCODINGs
和UNICODE
。您可以将其视为“转换表”(在此我进行了简化)。
code point
-这个很重要。甚至Microsoft的文档也没有像应该这样澄清。排序规则指定了如何对数据进行排序,比较,和存储!。是的,我敢打赌您没想到最后一个,对吧! ENCODING
上的排序规则也确定在特定UTF-8
/ ISO-8859-1
/ Windows-1252
/ ASCII
字段上使用的COLLATION
。>
SQL Server
-是最早的编码之一。它既是字符表(如ENCODING
的自己的小版本)又是其字节映射。因此,它不会将字节映射到char
,而是将字节映射到其自己的字符表。此外,它始终仅使用7位,并支持128个不同的字符。它足以支持所有英文字母的大写和小写,数字,标点和其他一些有限的字符。 ASCII的问题在于,由于当时它仅使用7位,并且几乎每台计算机都使用8位,因此还有另外128种可能的字符被“探索”,并且每个人都开始将“可用”字节映射到自己的字符表中,创建了许多不同的nchar
。
varchar
-这是另一个nvarchar
,是ASCII ENCODING
中使用次数最多(如果不是最多的话)之一。它使用可变的字节宽度(根据规范,一个字符的长度可以从1到6个字节),并且完全支持所有UNICODE
字符。
UNICODE
-也是最常用的ENCODINGs
之一,它在SQL Server上被广泛使用。它是固定大小的,因此每个字符始终为1个字节。它还支持多种语言的重音,但是不支持所有现有的重音,也不支持UTF-8 ENCODING
。 这就是为什么您的ENCODING
字段具有常见的排序规则,例如ENCODING
支持UNICODE
,Windows-1252 ENCODING
,ENCODING
字符,即使它没有使用支持UNICODE
varchar
。
资源:
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-collation-name-transact-sql?view=sql-server-ver15
https://docs.microsoft.com/en-us/sql/t-sql/statements/sql-server-collation-name-transact-sql?view=sql-server-ver15
https://docs.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-ver15#SQL-collations
SQL Server default character encoding
https://en.wikipedia.org/wiki/Windows_code_page
答案 3 :(得分:3)
希腊语在N列类型上需要UTF-8:αβγ;)
答案 4 :(得分:2)
我是西班牙语母语,“ch”不是一个字母,而是两个“c”和“h”,西班牙字母表如下: abcdefghijklmn - opqrstuvwxyz 我们不期望“h”之后的“ch”而是“i” 除了ñ或HTML“&amp; ntilde;”
外,字母与英文相同亚历
答案 5 :(得分:0)
<强> TL; DR; 强>
Unicode - (nchar,nvarchar和ntext)
非unicode - (char,varchar和text)。
SQL Server中的排序规则提供排序规则,大小写和重音 数据的敏感性属性。与之一起使用的排序规则 字符数据类型(如char和varchar)指示代码页 以及可以为该数据表示的相应字符 类型。
假设您正在使用默认SQL排序规则SQL_Latin1_General_CP1_CI_AS
,那么下面的脚本应该打印出您可以放在VARCHAR
中的所有符号,因为它使用一个字节来存储一个字符(总共256个)在打印的列表中看到它 - 您需要NVARCHAR
。
declare @i int = 0;
while (@i < 256)
begin
print cast(@i as varchar(3)) + ' '+ char(@i) collate SQL_Latin1_General_CP1_CI_AS
print cast(@i as varchar(3)) + ' '+ char(@i) collate Japanese_90_CI_AS
set @i = @i+1;
end
如果您更改排序规则,让我们说日语,您会注意到所有奇怪的欧洲字母变为正常,而某些符号变为?
标记。
Unicode是将代码点映射到字符的标准。因为 它旨在涵盖所有语言的所有字符 世界上,不需要不同的代码页来处理不同的 字符组。如果存储反映多个的字符数据 语言,始终使用Unicode数据类型(nchar,nvarchar和ntext) 而不是非Unicode数据类型(char,varchar和text)。
否则你的排序会很奇怪。
答案 6 :(得分:0)
如果有人在Mysql中遇到此问题,则无需将varchar更改为nvarchar,您只需将列的排序规则更改为utf8