Pourquoi le type de données varchar autorise-t-il les valeurs unicode?


17

J'ai une table avec une colonne varchar. Il autorise les marques déposées (™), les droits d'auteur (©) et d'autres caractères Unicode comme indiqué ci-dessous.

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

Mais la définition de varchar indique qu'elle autorise les données de chaîne non unicode. Mais les symboles Trademark (™) et Registered (®) sont des caractères Unicode . La définition contredit-elle la propriété du type de données varchar? J'ai lu quelques liens comme le premier et le deuxième . Mais je ne pouvais toujours pas comprendre pourquoi il autorise la chaîne unicode lorsque la définition dit qu'il n'autorise que les valeurs de chaîne non unicode.


12
Tous les caractères sont des caractères Unicode.
Martin Smith

Microsoft utilise souvent UNICODE quand il signifie UTF-16 / UCS-2. Donc, ils pourraient même ne pas compter UTF-8 car UNICODE est un certain contexte.
CodesInChaos

1
@CodesInChaos: J'ai eu du mal à analyser votre commentaire, mais je crains que vous ne confondiez Unicode avec les différents encodages UTF-n.
Courses de légèreté avec Monica

1
@Martin Smith: Si tous les caractères sont des caractères Unicode, alors pourquoi la définition de Microsoft varchar indique-t-elle qu'elle autorise les données de chaîne non Unicode?
Shiva

2
l'encodage des caractères dans varchar n'est pas unicode mais tous les caractères existent en unicode
Martin Smith

Réponses:


15

Mais les symboles Trademark (™) et Registered (®) sont des caractères Unicode.

Vous avez tort ici. Vos chaînes ne contiennent que des asciicaractères.

Voici un test simple qui vous montre que vos personnages sont tous des ascii (+ certains extended asciiavec des codes ascii entre 128 et 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;

Ici, vous pouvez clairement voir que tous vos caractères sont codés sur 1 octet:

entrez la description de l'image ici

Oui, ce ne sont pas des caractères ascii purs mais ils sont en ASCII étendu .

Ici, je vous montre le vrai caractère unicode Trademark(™)et son code et sa représentation binaire:

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;

entrez la description de l'image ici

Enfin, vous pouvez voir que le Trademark(™)caractère unicode a le code 8482 et non 153:

select nchar(8482), nchar(153)

1
Mais il n'y a pas de mot "ASCII" dans l'article que vous avez mentionné, ils parlent uniquement de caractères unicode et non unicode, et la marque déposée (™) que vous avez utilisée n'était pas unicode.
septembre 2018

16
"ASCII étendu" est un terme horriblement ambigu. Il serait plus utile de voir quel encodage 8 bits est réellement utilisé (est-il basé sur les paramètres régionaux / de classement?). Je devine la page de codes Windows 1252 , qui encode en effet ™ en tant que caractère 153.
IMSoP

2
@sepupic Je pense que vous devez en savoir plus sur la différence entre les points de code et les encodages. Wikipedia peut aider. "Un codage mappe (éventuellement un sous-ensemble de) la plage de codes Unicode pointe vers des séquences de valeurs dans une plage de taille fixe, appelées valeurs de code ." 8482 est le point de code pour ™, qui peut être encodé en tant que \ x99 (153) dans Windows-1252, en tant que \ xAA dans MacRoman, en tant que \ xE2 \ x84 \ xA2 en UTF-8, etc.
curiousdannii

7
Des précautions doivent être prises avec les caractères 8 bits au-dessus de 127: ce que chaque code au-dessus de 127 représente peut et changera en fonction de l'encodage utilisé qui variera en fonction du classement utilisé. Dans la page de codes 1252, l'unicode 8482 est mappé à 153. Dans la page de codes 850, ce point est pris par 214 ( Ö) et dans ISO-8859-1 (parfois appelé Latin1), c'est un code de contrôle sans représentation imprimable. Sauf si vous savez que vous utiliserez toujours la même page de code, il est plus sûr de s'en tenir aux caractères ANSI (127 ou moins) ou d'utiliser des types Unicode. La page de codes 1252 est la plus courante dans SQL Server mais loin d'être omniprésente.
David Spillett

4
@Shiva Le minimum absolu Chaque développeur de logiciels doit absolument, positivement, connaître Unicode et les jeux de caractères . ASCII est un sous-ensemble de nombreux encodages, et presque tous ces encodages contiennent des symboles non ASCII et ne sont pas simultanément Unicode. Et Unicode a également de nombreux encodages différents (tels que UTF-8, UTF-32, etc.).
jpmc26

7

D'après les commentaires, je suis d'accord "ASCII étendu" est un terme vraiment mauvais qui signifie en fait une page de codes qui mappe les caractères / points de code dans la plage 128-255, au-delà de la plage de points de code 0-127 standard définie par ASCII.

SQL Server prend en charge de nombreuses pages de codes via des classements. Les caractères non ASCII peuvent être stockés dans varchar tant que le classement sous-jacent prend en charge le caractère.

Le caractère «™» peut être stocké dans des colonnes varchar / char lorsque la page de codes de classement SQL Server est supérieure ou égale à 1250. La requête ci-dessous les énumérera:

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

Mais seul un sous-ensemble de ceux-ci prend également en charge le caractère «©», de sorte que le classement des colonnes devra être l'un des suivants pour prendre en charge les deux:

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;

4

Mais la définition de varchar indique qu'elle autorise les données de chaîne non unicode . Mais les symboles des marques (™) et enregistré (®) sont Unicode caractères . La définition contredit-elle la propriété du type de données varchar?

Bien que les autres réponses ne soient pas incorrectes, je pense qu'il serait utile de signaler une confusion dans la terminologie de base. J'ai souligné deux mots dans la citation ci-dessus de la question comme exemple de cette confusion. Lorsque la documentation SQL Server parle d'Unicode et non-Unicode des données , ils ne parlent des personnages . Ils parlent des séquences d'octets qui représentent certains caractères. La principale différence entre les types Unicode ( NCHAR, NVARCHAR, XMLet le dépréciée / mal NTEXT) et les types non-Unicode ( CHAR, VARCHARet le dépréciée / mal TEXT) est ce que les types de séquences d'octets qu'ils peuvent stocker.

Les types non Unicode stockent l'un des nombreux codages 8 bits, tandis que les types Unicode stockent un seul codage Unicode 16 bits: UTF-16 Little Endian. Comme les autres réponses l'ont mentionné, quels caractères peuvent être stockés dans un codage 8 bits / non Unicode dépend de la page de codes, qui est déterminée par le classement. Alors que d'autres ont noté que la valeur en octets d'un "caractère" peut varier selon les pages de codes sur lesquelles il se trouve, la valeur en octets peut même varier au sein de la même page de codes lorsqu'il s'agit de l'une des plusieurs pages de codes EBCDIC (variations de Windows- 1252), qui ne se trouvent que dans les anciennes versions de SQL Server, ne devraient pas vraiment être utilisées (c'est-à-dire celles dont le nom commence par SQL_).

Par conséquent, la définition est précise: tous les caractères que vous pouvez gérer pour stocker dans un type non Unicode sont toujours 8 bits (même s'ils utilisent deux valeurs 8 bits en combinaison comme un seul "caractère", ce qui est ce que le Double- Le jeu de caractères octet / les pages de codes DBCS le permettent). Et les types de données Unicode sont toujours 16 bits, même s'ils utilisent parfois deux valeurs 16 bits en combinaison comme un seul "caractère" (c'est-à-dire une paire de substitution qui à son tour représente un caractère supplémentaire).

ET, en raison de la prise en charge native de SQL Server pour le codage UTF-8 VARCHARet les CHARtypes de données à partir de SQL Server 2019,

VARCHARne peut plus être appelé "non-Unicode". Donc, à partir de la première version bêta publique de SQL Server 2019 en septembre 2018, nous devrions nous référer à VARCHARun "type de données 8 bits", même lorsque nous parlons en termes de versions antérieures à SQL Server 2019. Cette terminologie est vraie pour les 4 types d'encodages utilisables avec VARCHAR:

  1. ASCII étendu
  2. Jeux de caractères codés sur deux octets (DBCS)
  3. EBCDIC
  4. UTF-8 (Unicode)

Seul le TEXTtype de données (obsolète à partir de SQL Server 2005, donc ne l'utilisez pas) est "non-Unicode", mais ce n'est qu'une technicité, et le qualifier de "type de données 8 bits" est exact.

NVARCHAR,, NCHARet NTEXTpeut être appelé "UTF-16" ou "type de données 16 bits". Oracle, je crois, utilise la terminologie de "Unicode uniquement" pour NVARCHAR, mais cela n'exclut pas clairement la possibilité d'utiliser UTF-8 (également un encodage Unicode), qui ne fonctionnera pas, donc il vaut probablement mieux s'en tenir à les deux premières options.

Pour plus de détails sur les nouveaux encodages UTF-8, veuillez consulter mon article:

Prise en charge native UTF-8 dans SQL Server 2019: Sauveur ou faux prophète?

PS Je progresse lentement vers la mise à jour de la documentation SQL Server pour refléter ces changements.

PPS Microsoft a déjà mis à jour certaines pages avec des informations UTF-8, y compris la documentation char et varchar référencée dans la question. Il ne contient plus l'expression "non-Unicode". Mais ce n'est qu'un FYI; cela ne change pas la question car il s'agit d'encodages non Unicode contenant des caractères qui étaient à tort pensés être uniquement Unicode.


3

La question contient une idée fausse centrale sur ce qu'est Unicode. Le jeu de caractères Unicode, ainsi que ses encodages tels que UTF-8 et UTF-16, est l'une des nombreuses façons de représenter le texte dans un ordinateur, et dont le but est de remplacer tous les autres jeux de caractères et encodages. Si "données non Unicode" signifiait "caractères non présents dans Unicode", alors aucun du texte que j'ai utilisé dans cette réponse ne pourrait être stocké dans ce type, car toutes les lettres de l'alphabet latin et la ponctuation courante utilisées dans l'anglais courant sont inclus dans Unicode.

Les représentations textuelles peuvent être globalement envisagées en deux parties: un jeu de caractères mappant les différents caractères (lettres, chiffres, symboles, etc.) aux nombres sur un graphique de référence; et un codage représentant ces nombres sous forme de modèles de bits (sur disque, via une connexion réseau, etc.). Ici, nous nous intéressons principalement à la première partie: quels caractères sont répertoriés dans les graphiques pour un jeu de caractères particulier.

Étant donné qu'Unicode vise à avoir des nombres (qu'il appelle des "points de code") pour chaque caractère dans le monde, des références comme Wikipedia se réfèrent souvent à la position Unicode d'un caractère comme une information standard de référence. Cependant, cela ne signifie pas que les autres jeux de caractères n'ont pas de mappage pour ce même caractère.

L'un des jeux de caractères (et codages) les plus anciens et les plus simples encore en usage est ASCII, qui a des mappages pour 128 caractères différents (0 à 127), car il utilise 7 bits pour coder chaque caractère. Étant donné que cela exclut de nombreux caractères accentués et symboles communs, les codages ultérieurs utilisent 8 bits et mappent les mêmes 128 premiers caractères, ajoutant au jeu de caractères en remplissant les positions 128 à 255. Parmi ceux-ci figurent les normes ISO 8859-1 et ISO 8859- 15 , et la page de codes Windows spécifique à Microsoft 1252 .

Donc, pour revenir à MS SQL Server: une "chaîne Unicode", telle qu'elle est stockée dans une nchar, nvarcharou une ntextcolonne, peut représenter tous les caractères mappés dans le jeu de caractères Unicode, car elle utilise un codage Unicode pour stocker les données. Une « chaîne non Unicode », telle qu'elle est stockée dans une char, varcharou textcolonne, peuvent représenter uniquement les caractères mis en correspondance dans un autre codage . Tout ce que vous pouvez stocker dans une colonne non Unicode peut également être stocké dans une colonne Unicode, mais pas l'inverse.

Pour savoir exactement quels caractères vous pouvez stocker, vous devez connaître le "classement" utilisé, qui dicte ce que Microsoft appelle une "page de code", comme expliqué sur cette page de référence Microsoft . Il est probable que dans votre cas, vous utilisez la page de code très courante 1252, que j'ai mentionnée plus tôt.

Les caractères que vous avez mentionnés existent à la fois dans Unicode et dans la page de code 1252:

  • Trademark (™) apparaît en Unicode à la position 8482 et en CP1252 à la position 153
  • Enregistré (®), en l'occurrence, apparaît à la fois dans Unicode et CP1252 à la position 174

3
«Unicode est l'une des nombreuses façons de coder du texte à utiliser sur un ordinateur» - Ce n'est pas correct. Unicode est juste une collection de caractères et de symboles, où chaque caractère a son propre point de code unique qui n'est qu'un nombre. Le travail d'un codage consiste alors à faire correspondre ces points de code à une séquence d'octets. UTF-8 et UTF-16 sont des encodages, Unicode ne l'est pas.
poke

@poke Comme je continue à dire plus loin dans la réponse, j'utilise ici "codage" pour représenter à la fois "le mappage des caractères aux positions sur un graphique" et "les représentations de ces positions comme une séquence de bits". Il y a peut-être un meilleur terme à utiliser, mais je ne suis pas sûr de ce que ce serait.
IMSoP

3
Eh bien, vous ne pouvez pas simplement utiliser le «codage» avec votre propre définition. Désolé de tergiverser ici, mais vous ne pouvez pas le faire dans une réponse qui s'ouvre avec "la question contient une idée fausse centrale sur ce qu'est Unicode" .
poke

2
IMSoP (et @poke): Je suis entièrement d'accord avec Poke concernant la portée excessive de l'utilisation du "codage" pour signifier autre chose que le codage, bien que je sois également favorable au dilemme d'IMSO. Ma préférence est de se référer à Unicode comme un jeu de caractères qui a plusieurs encodages, alors que généralement le jeu de caractères et l'encodage sont utilisés de manière interchangeable car ils sont une relation 1 à 1 la plupart (ou peut-être tous?) Du temps.
Solomon Rutzky

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.