Eu tenho uma tabela com uma coluna varchar. Está permitindo Trademark(™), copyright(©) e outros caracteres Unicode, conforme mostrado abaixo.
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
Mas a definição de varchar diz que permite dados de string não unicode. Mas os símbolos Trademark(™) e Registered(®) são caracteres Unicode . A definição contradiz a propriedade do tipo de dados varchar? Eu li alguns links como o primeiro e o segundo . Mas ainda não consegui entender por que ele permite string unicode quando a definição diz que permite apenas valores de string não unicode.
Você está errado aqui. Suas strings contêm apenas caracteres ASCII.
Aqui está um teste simples que mostra que seus caracteres são todos ASCII (+ alguns ASCII estendidos com códigos ASCII entre 128 e 255):
Aqui você pode ver claramente que todos os seus caracteres são codificados em 1 byte:
Sim, eles não são caracteres ASCII puros, mas são ASCII estendidos .
Aqui eu mostro o caractere Unicode real
Trademark(™)
e seu código e representação binária:Finalmente, você pode ver que o caractere Unicode Trademark(™) tem código 8482 e não 153:
Pelos comentários, concordo que "Extended ASCII" é um termo muito ruim que na verdade significa uma página de código que mapeia caracteres/pontos de código no intervalo 128-255, além do intervalo de ponto de código padrão 0-127 definido pelo ASCII.
O SQL Server oferece suporte a muitas páginas de código por meio de agrupamentos. Caracteres não ASCII podem ser armazenados em varchar, desde que a ordenação subjacente suporte o caractere.
O caractere '™' pode ser armazenado em colunas varchar/char quando a página de código de agrupamento do SQL Server for 1250 ou superior. A consulta abaixo listará estes:
Mas apenas um subconjunto deles também suporta o caractere '©', portanto, o agrupamento de colunas precisará ser um dos seguintes para oferecer suporte a ambos:
Embora as outras respostas não estejam incorretas, acho que ajudaria apontar uma confusão na terminologia básica. Eu enfatizei duas palavras na citação acima da pergunta como um exemplo dessa confusão. Quando a documentação do SQL Server fala de dados Unicode e não Unicode , eles não estão falando sobre os caracteres . Eles estão falando das sequências de bytes que representam determinados caracteres. A principal diferença entre os tipos Unicode (
NCHAR
,NVARCHAR
,XML
, e o obsoleto / evilNTEXT
) e os tipos não Unicode (CHAR
,VARCHAR
, e o obsoleto / evilTEXT
) são os tipos de sequências de bytes que eles podem armazenar.Os tipos não Unicode armazenam uma das várias codificações de 8 bits, enquanto os tipos Unicode armazenam uma única codificação Unicode de 16 bits: UTF-16 Little Endian. Como as outras respostas mencionaram, quais caracteres podem ser armazenados em uma codificação de 8 bits / não Unicode depende da página de código, que é determinada pelo Collation. Enquanto outros notaram que o valor do byte de um "caractere" pode variar entre as páginas de código em que ele é encontrado, o valor do byte pode até variar dentro da mesma página de código ao lidar com uma das várias páginas de código EBCDIC (variações de Windows- 1252), que são encontrados apenas no SQL Server Collations mais antigos e que não deveriam ser usados (ou seja, aqueles com nomes começando com
SQL_
).Portanto, a definição é precisa: quaisquer caracteres que você consiga armazenar em um tipo não Unicode são sempre de 8 bits (mesmo que usem dois valores de 8 bits em combinação como um único "caracter", que é o que o Double- Byte Character Set / páginas de código DBCS permitem). E os tipos de dados Unicode são sempre de 16 bits, mesmo que às vezes usem dois valores de 16 bits em combinação como um único "caractere" (ou seja, um par substituto que, por sua vez, representa um caractere suplementar).
E, devido ao suporte nativo do SQL Server à codificação UTF-8
VARCHAR
e aosCHAR
tipos de dados a partir do SQL Server 2019,VARCHAR
não pode mais ser chamado de "não-Unicode". Portanto, começando com a primeira versão beta pública do SQL Server 2019 em setembro de 2018, devemos nos referirVARCHAR
como um "tipo de dados de 8 bits", mesmo quando falamos de versões anteriores ao SQL Server 2019. Essa terminologia é válida para todos os 4 tipos de codificações que podem ser usadas comVARCHAR
:Apenas o tipo de
TEXT
dados (desatualizado a partir do SQL Server 2005, portanto, não o use) é "não-Unicode", mas isso é apenas um detalhe técnico, e referir-se a ele como um "tipo de dados de 8 bits" é preciso.NVARCHAR
,NCHAR
, eNTEXT
pode ser referido como "UTF-16" ou um "tipo de dados de 16 bits". A Oracle, acredito, usa a terminologia de "somente Unicode" paraNVARCHAR
, mas isso não exclui claramente a possibilidade de usar UTF-8 (também uma codificação Unicode), que não funcionará, então provavelmente é melhor ficar com as duas primeiras opções.Para obter detalhes sobre as novas codificações UTF-8, consulte minha postagem:
Suporte nativo a UTF-8 no SQL Server 2019: Salvador ou Falso Profeta?
PS Estou trabalhando lentamente na atualização da documentação do SQL Server para refletir essas alterações.
PPS A Microsoft já atualizou algumas páginas com informações de UTF-8, incluindo a documentação de char e varchar referenciada na pergunta. Ele não contém mais a frase "não-Unicode". Mas isso é apenas um FYI; isso não altera a pergunta, pois trata-se de codificações não Unicode contendo caracteres que foram erroneamente considerados apenas Unicode.
A questão contém um equívoco central sobre o que é Unicode. O conjunto de caracteres Unicode, juntamente com suas codificações, como UTF-8 e UTF-16, é uma das muitas maneiras de representar texto em um computador e cujo objetivo é substituir todos os outros conjuntos de caracteres e codificações. Se "dados não Unicode" significasse "caracteres não presentes no Unicode", nenhum texto que usei nesta resposta poderia ser armazenado nesse tipo, porque todas as letras do alfabeto latino e a pontuação comum usadas no inglês cotidiano são incluído no Unicode.
As representações de texto podem ser divididas em duas partes: um conjunto de caracteres mapeando os diferentes caracteres (letras, dígitos, símbolos, etc) para números em um gráfico de referência; e uma codificação representando esses números como padrões de bits (no disco, em uma conexão de rede, etc). Aqui estamos principalmente preocupados com a primeira parte: quais caracteres são listados nos gráficos para um conjunto de caracteres específico.
Como o Unicode visa ter números (que ele chama de "pontos de código") para cada caractere do mundo, referências como a Wikipedia geralmente se referem à posição Unicode de um caractere como uma informação padrão de referência. No entanto, isso não significa que outros conjuntos de caracteres também não tenham um mapeamento para esse mesmo caractere.
Um dos conjuntos de caracteres (e codificações) mais antigos e simples ainda em uso é o ASCII, que possui mapeamentos para 128 caracteres diferentes (0 a 127), pois utiliza 7 bits para codificar cada caractere. Como isso exclui muitos caracteres acentuados e símbolos comuns, as codificações posteriores usam 8 bits e mapeiam os mesmos primeiros 128 caracteres, adicionando ao conjunto de caracteres preenchendo as posições 128 a 255. Entre eles, destacam-se os padrões ISO 8859-1 e ISO 8859- 15 e a página de código do Windows específica da Microsoft 1252 .
Então, voltando ao MS SQL Server: uma "string Unicode", conforme armazenada em uma coluna , , ou , pode representar
nchar
todosnvarchar
os caracteres mapeados no conjunto de caracteres Unicode, pois usa uma codificação Unicode para armazenar os dados. Uma "string não Unicode", conforme armazenada em uma coluna , , ou pode representar apenas os caracteres mapeados em alguma outra codificação . Qualquer coisa que você possa armazenar em uma coluna não Unicode também pode ser armazenada em uma coluna Unicode, mas não vice-versa.ntext
char
varchar
text
Para saber exatamente quais caracteres você pode armazenar, você precisa conhecer o "agrupamento" em uso, que determina o que a Microsoft chama de "página de código", conforme explicado nesta página de referência da Microsoft . É provável que no seu caso você esteja usando a página de código 1252 muito comum, que mencionei anteriormente.
Os caracteres que você mencionou existem em Unicode e Code Page 1252:
Aceitar algo e SOMENTE aceitar algo NÃO são a mesma coisa. Se você for a um drive-thru que diz "aceitamos notas de $ 50", isso significa que eles SÓ aceitam notas de $ 50? Claro que não. Da mesma forma, nem aceita Unicode e APENAS aceita Unicode o mesmo. Você adicionou a palavra "SOMENTE" onde, de acordo com sua pergunta, ela não existia na definição que você citou.