Solución:
La verdadera razón por la que desea utilizar NVARCHAR es cuando tiene diferente idiomas en la misma columna, debe abordar las columnas en T-SQL sin decodificar, desea poder ver los datos “de forma nativa” en SSMS o desea estandarizar en Unicode.
Si trata la base de datos como un almacenamiento tonto, es perfectamente posible almacenar cadenas anchas y codificaciones diferentes (incluso de longitud variable) en VARCHAR (por ejemplo, UTF-8). El problema surge cuando intenta codificar y decodificar, especialmente si la página de códigos es diferente para diferentes filas. También significa que SQL Server no podrá manejar los datos fácilmente para realizar consultas dentro de T-SQL en columnas codificadas (potencialmente de forma variable).
Usar NVARCHAR evita todo esto.
Recomendaría NVARCHAR para cualquier columna que contenga datos ingresados por el usuario y que esté relativamente libre de restricciones.
Recomendaría VARCHAR para cualquier columna que sea una clave natural (como la placa de un vehículo, SSN, número de serie, etiqueta de servicio, número de pedido, indicativo del aeropuerto, etc.) que normalmente está definida y limitada por una norma, legislación o convención. También VARCHAR para usuario ingresado y muy restringido (como un número de teléfono) o un código (ACTIVO / CERRADO, S / N, M / F, M / S / D / W, etc.). No hay absolutamente ninguna razón para usar NVARCHAR para esos.
Entonces, para una regla simple:
VARCHAR cuando se garantiza que estará restringido NVARCHAR de lo contrario
Debe usar NVARCHAR siempre que tenga que almacenar varios idiomas. Creo que debe usarlo para los idiomas asiáticos, pero no me cite.
Aquí está el problema si toma el ruso, por ejemplo, y lo almacena en un varchar, estará bien siempre que defina la página de códigos correcta. Pero digamos que está utilizando una instalación predeterminada de sql en inglés, entonces los caracteres rusos no se manejarán correctamente. Si estuviera utilizando NVARCHAR (), se manejarían correctamente.
Editar
Ok, déjeme citar MSDN y tal vez sea demasiado específico, pero no desea almacenar más de una página de códigos en una columna varcar, mientras que puede, no debería
Cuando maneja datos de texto que se almacenan en el tipo de datos char, varchar, varchar (max) o text, la limitación más importante a considerar es que el sistema solo puede validar la información de una sola página de códigos. (Puede almacenar datos de varias páginas de códigos, pero esto no se recomienda). La página de códigos exacta utilizada para validar y almacenar los datos depende de la clasificación de la columna. Si no se ha definido una intercalación a nivel de columna, se utiliza la intercalación de la base de datos. Para determinar la página de códigos que se usa para una columna determinada, puede usar la función COLLATIONPROPERTY, como se muestra en los siguientes ejemplos de código:
Aquí hay algo más:
Este ejemplo ilustra el hecho de que muchas configuraciones regionales, como georgiano e hindi, no tienen páginas de códigos, ya que son intercalaciones solo Unicode. Esas intercalaciones no son apropiadas para columnas que usan el tipo de datos char, varchar o text.
Por lo tanto, el georgiano o el hindi realmente deben almacenarse como nvarchar. El árabe también es un problema:
Otro problema que puede encontrar es la incapacidad de almacenar datos cuando no todos los caracteres que desea admitir están contenidos en la página de códigos. En muchos casos, Windows considera que una página de códigos en particular es la página de códigos “que mejor se ajusta”, lo que significa que no hay garantía de que pueda confiar en la página de códigos para manejar todo el texto; es simplemente el mejor disponible. Un ejemplo de esto es la escritura árabe: admite una amplia gama de idiomas, incluidos baluchi, bereber, farsi, cachemira, kazajo, kirguís, pashto, sindhi, uigur, urdu y más. Todos estos idiomas tienen caracteres adicionales además de los del idioma árabe según se define en la página de códigos 1256 de Windows. Si intenta almacenar estos caracteres adicionales en una columna que no sea Unicode que tenga la intercalación árabe, los caracteres se convertirán en signos de interrogación.
Algo a tener en cuenta cuando usa Unicode, aunque puede almacenar diferentes idiomas en una sola columna, solo puede ordenarlos usando una sola intercalación. Hay algunos idiomas que usan caracteres latinos pero no se clasifican como otros idiomas latinos. Los acentos son un buen ejemplo de esto, no recuerdo el ejemplo, pero había un idioma de Europa del Este cuya Y no se clasificaba como la Y en inglés. Luego está la ch en español que los usuarios españoles esperan que se clasifique después de h.
Considerándolo todo con todos los problemas con los que tiene que lidiar cuando se trata de internalización. En mi opinión, es más fácil usar caracteres Unicode desde el principio, evitar las conversiones adicionales y aprovechar el espacio. De ahí mi declaración anterior.
Las dos respuestas más votadas son incorrectas. No debería tener nada que ver con “almacenar diferentes / múltiples idiomas”. Puedes admitir caracteres españoles como ñ
e inglés, con solo comunes varchar
campo y Latin1_General_CI_AS
COLLATION
, p.ej
Version corta
Deberías usar NVARCHAR
/NCHAR
siempre que el ENCODING
, que está determinada por COLLATION
del campo, no admite los caracteres necesarios.
Además, según la versión de SQL Server, puede utilizar COLLATIONs
, igual que Latin1_General_100_CI_AS_SC_UTF8
que está disponible desde SQL Server 2019. Establecer esta intercalación en un VARCHAR
campo (o toda la tabla / base de datos), utilizará UTF-8
ENCODING
para almacenar y manejar los datos en ese campo, lo que permite un soporte total UNICODE
personajes, y por lo tanto, cualquier idioma adoptado por él.
PARA ENTENDER COMPLETAMENTE:
Para comprender completamente lo que voy a explicar, es obligatorio tener los conceptos de UNICODE
, ENCODING
y COLLATION
todo extremadamente claro en tu cabeza. Si no es así, primero eche un vistazo a mi humilde y simplificada explicación sobre “Qué es UNICODE, ENCODING, COLLATION y UTF-8, y cómo se relacionan” sección y enlaces de documentación suministrados. Además, todo lo que digo aquí es específico para Microsoft SQL Server
y cómo almacena y maneja los datos en char
/nchar
y varchar
/nvarchar
los campos.
Digamos que queremos almacenar un texto peculiar en nuestra base de datos del servidor MSSQL. Podría ser un comentario de Instagram como “¡Me encanta stackoverflow!”.
La parte en inglés simple sería perfectamente compatible incluso con ASCII, pero dado que también hay un emoji, que es un carácter especificado en el UNICODE
estándar, necesitamos un ENCODING
que admite este carácter Unicode.
MSSQL Server utiliza el COLLATION
para determinar que ENCODING
se usa en char
/nchar
/varchar
/nvarchar
los campos. Entonces, a diferencia de lo que muchos piensan, COLLATION
no es sólo sobre ordenar y comparar datos, sino también sobre ENCODING
, y por consecuencia: ¡Cómo se almacenarán nuestros datos!
Entonces, ¿CÓMO SABEMOS CUÁL ES LA CODIFICACIÓN QUE UTILIZA NUESTRA COLLACIÓN? Con este:
SELECT COLLATIONPROPERTY( 'Latin1_General_CI_AI' , 'CodePage' ) AS [CodePage]
--returns 1252
Este simple SQL devuelve el Windows Code Page
para COLLATION
. A Windows Code Page
no es más que otro mapeo para ENCODINGs
. Para el Latin1_General_CI_AI
COLLATION
devuelve el Windows Code Page
código 1252
, que se asigna a Windows-1252
ENCODING
.
Entonces, por un varchar
columna, con Latin1_General_CI_AI
COLLATION
, este campo manejará sus datos usando el Windows-1252
ENCODING
, y solo almacena correctamente los caracteres admitidos por esta codificación.
Si comprobamos el Windows-1252 ENCODING
Especificación Lista de caracteres para Windows-1252, descubriremos que esta codificación no es compatible con nuestro carácter emoji. Y si todavía lo probamos:
OK, ¿CÓMO PODEMOS RESOLVER ESTO? De hecho, depende, ¡y eso es BUENO!
NCHAR
/NVARCHAR
Antes de SQL Server 2019, todo lo que teníamos era NCHAR
y NVARCHAR
los campos. Algunos dicen que son UNICODE
los campos. ¡ESO ESTÁ MAL!. Nuevamente, depende de la COLLATION
y también Versión SQLServer. La documentación “nchar y nvarchar (Transact-SQL)” de Microsoft especifica perfectamente:
A partir de SQL Server 2012 (11.x), cuando se usa una intercalación habilitada para caracteres suplementarios (SC), estos tipos de datos almacenan el rango completo de datos de caracteres Unicode y usan la codificación de caracteres UTF-16. Si se especifica una intercalación no SC, estos tipos de datos almacenan solo el subconjunto de datos de caracteres admitidos por la codificación de caracteres UCS-2.
En otras palabras, si usamos SQL Server anterior a 2012, como SQL Server 2008 R2 por ejemplo, el ENCODING
para esos campos usará UCS-2 ENCODING
que admiten un subconjunto de UNICODE
. Pero si usamos SQL Server 2012 o más reciente, y definimos un COLLATION
que tiene Supplementary Character
habilitado, que con nuestro campo usaremos el UTF-16
ENCODING
, que apoya plenamente UNICODE
.
¡PERO, HAY MÁS! ¡PODEMOS USAR UTF-8 AHORA!
CHAR
/VARCHAR
A partir de SQL Server 2019, NOSOTROS PODEMOS USAR CHAR
/VARCHAR
campos y aún ser totalmente compatible UNICODE
utilizando UTF-8
ENCODING
!!!
De la documentación “char and varchar (Transact-SQL)” de Microsoft:
A partir de SQL Server 2019 (15.x), cuando se usa una intercalación habilitada para UTF-8, estos tipos de datos almacenan el rango completo de datos de caracteres Unicode y usan la codificación de caracteres UTF-8. Si se especifica una intercalación que no es UTF-8, estos tipos de datos almacenan solo un subconjunto de caracteres admitidos por la página de códigos correspondiente de esa intercalación.
Nuevamente, en otras palabras, si usamos SQL Server anterior a 2019, como SQL Server 2008 R2, por ejemplo, debemos verificar el ENCODING
utilizando el método explicado anteriormente. Pero si usamos SQL Server 2019 o más reciente, y definimos un COLLATION
igual que Latin1_General_100_CI_AS_SC_UTF8
, entonces nuestro campo usará UTF-8
ENCODING
que es, con mucho, la codificación más utilizada y eficiente que admite todas las UNICODE
caracteres.
Información adicional:
En cuanto a la observación del PO sobre “He visto que la mayoría de los idiomas europeos (alemán, italiano, inglés, …) están bien en la misma base de datos en columnas VARCHAR”, Creo que es bueno saber por qué es:
Para los mas comunes COLLATIONs
, como los predeterminados como Latin1_General_CI_AI
o SQL_Latin1_General_CP1_CI_AS
los ENCODING
estarán Windows-1252
por varchar
los campos. Si echamos un vistazo a su documentación, podemos ver que admite:
Inglés, irlandés, italiano, noruego, portugués, español, sueco. Además también alemán, finlandés y francés. Y holandés excepto el carácter IJ
Pero como dije antes, no se trata de lenguaje, se trata de qué caracteres esperas apoyar / almacenar, como se muestra en el ejemplo de emoji, o alguna oración como “La resistencia eléctrica de una batería de litio es 0.5Ω” donde tenemos nuevamente inglés simple, y una letra / carácter griego “omega” (que es el símbolo de resistencia en ohmios), que no será manejado correctamente por Windows-1252
ENCODING
.
Conclusión:
¡Así que ahí está! Cuando se usa char
/nchar
y varchar
/nvarchar
depende de los caracteres que desea admitir, y también de la versión de su servidor SQL que determinará qué COLLATIONs
y de ahí el ENCODINGs
tienes disponible.
Qué es UNICODE, ENCODING, COLLATION y UTF-8, y cómo se relacionan
Nota: todas las explicaciones a continuación son simplificaciones. Consulte los enlaces de documentación suministrados para conocer todos los detalles sobre esos conceptos.
-
UNICODE
– Es un estándar, una convención, que tiene como objetivo regular todos los personajes en una tabla unificada y organizada. En esta tabla, cada carácter tiene un número único. Este número comúnmente se llama caráctercode point
.
¡UNICODE NO ES UNA CODIFICACIÓN! -
ENCODING
– Es un mapeo entre un carácter y una secuencia de bytes / bytes. Entonces, una codificación se usa para “transformar” un carácter en bytes y también al revés, de bytes a un carácter. Entre los más populares se encuentranUTF-8
,ISO-8859-1
,Windows-1252
yASCII
. Puede pensar en ello como una “tabla de conversión” (realmente simplificado aquí). -
COLLATION
– Ese es importante. Incluso la documentación de Microsoft no deja esto claro como debería ser. Una intercalación especifica cómo se ordenarían, compararían, ¡Y ALMACENADO!. Sí, apuesto a que no esperabas ese último, ¿verdad? Las colaciones enSQL Server
determina también cuál sería elENCODING
usado en ese particularchar
/nchar
/varchar
/nvarchar
campo. -
ASCII ENCODING
– Fue una de las primeras codificaciones. Es tanto la tabla de caracteres (como una propia versión diminuta deUNICODE
) y sus asignaciones de bytes. Entonces no asigna un byte aUNICODE
, pero asigna un byte a la tabla de su propio carácter. Además, siempre usa solo 7 bits y admite 128 caracteres diferentes. Fue suficiente para admitir todas las letras inglesas en mayúsculas y minúsculas, números, puntuación y algún otro número limitado de caracteres. El problema con ASCII es que dado que solo usaba 7 bits y casi todas las computadoras tenían 8 bits en ese momento, había otras 128 posibilidades de caracteres para ser “explorados”, y todos comenzaron a asignar estos bytes “disponibles” a su propia tabla de caracteres. , creando un montón de diferentesENCODINGs
. -
UTF-8 ENCODING
– Este es otroENCODING
, uno de los más (si no el más) utilizadosENCODING
alrededor. Utiliza un ancho de byte variable (un carácter puede tener de 1 a 6 bytes de largo, por especificación) y es totalmente compatible con todosUNICODE
caracteres. -
Windows-1252 ENCODING
– También uno de los más usadosENCODING
, se usa ampliamente en SQL Server. Tiene un tamaño fijo, por lo que cada carácter es siempre de 1 byte. También admite muchos acentos, de varios idiomas, pero no admite todos los existentes ni admiteUNICODE
. Es por eso que tuvarchar
campo con una colación común comoLatin1_General_CI_AS
apoyosá
,é
,ñ
personajes, incluso que no está utilizando un apoyoUNICODE
ENCODING
.
Recursos:
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
Codificación de caracteres predeterminada de SQL Server
https://en.wikipedia.org/wiki/Windows_code_page