sql >> Base de Datos >  >> RDS >> Sqlserver

Conversión de Unicode a no Unicode

Hay algunas cosas a tener en cuenta aquí:

  1. Si desea ver exactamente qué carácter está allí, puede convertir el valor a VARBINARY lo que le dará el valor hexadecimal/binario de todos los caracteres de la cadena y no existe el concepto de caracteres "ocultos" en hexadecimal:

    DECLARE @PostalCode NVARCHAR(20);
    SET @PostalCode = N'053000'+ NCHAR(0x2008); -- 0x2008 = "Punctuation Space"
    SELECT @PostalCode AS [NVarCharValue],
           CONVERT(VARCHAR(20), @PostalCode) AS [VarCharValue],
           CONVERT(VARCHAR(20), RTRIM(@PostalCode)) AS [RTrimmedVarCharValue],
           CONVERT(VARBINARY(20), @PostalCode) AS [VarBinaryValue];
    

    Devoluciones:

    NVarCharValue   VarCharValue   RTrimmedVarCharValue   VarBinaryValue
    053000          053000?        053000?                0x3000350033003000300030000820
    

    NVARCHAR los datos se almacenan como UTF-16, que funciona en conjuntos de 2 bytes. Mirando los últimos 4 dígitos hexadecimales para ver cuál es el conjunto oculto de 2 bytes, vemos "0820". Dado que Windows y SQL Server son UTF-16 Little Endian (es decir, UTF-16LE), los bytes están en orden inverso. Volteando los últimos 2 bytes -- 08 y 20 -- obtenemos "2008", que es el "Espacio de puntuación" que agregamos a través de NCHAR(0x2008) .

    Además, tenga en cuenta que RTRIM no ayudó en absoluto aquí.

  2. De manera simplista, puede simplemente reemplazar los signos de interrogación con nada:

    SELECT REPLACE(CONVERT(VARCHAR(20), [PostalCode]), '?', '');
    
  3. Más importante aún, debe convertir el [PostalCode] campo a VARCHAR para que no almacene estos caracteres. Ningún país usa letras que no estén representadas en el conjunto de caracteres ASCII y que no sean válidas para el tipo de datos VARCHAR, al menos por lo que he leído (consulte la sección inferior para obtener referencias). De hecho, lo que está permitido es un subconjunto bastante pequeño de ASCII, lo que significa que puede filtrar fácilmente al entrar (o simplemente hacer lo mismo REPLACE como se muestra arriba al insertar o actualizar):

    ALTER TABLE [table] ALTER COLUMN [PostalCode] VARCHAR(20) [NOT]? NULL;
    

    Asegúrese de verificar el NULL actual / NOT NULL ajuste para la columna y hágalo igual en la instrucción ALTER anterior; de lo contrario, podría cambiarse ya que el valor predeterminado es NULL si no se especifica.

  4. Si no puede cambiar el esquema de la tabla y necesita hacer una "limpieza" periódica de los datos incorrectos, puede ejecutar lo siguiente:

    ;WITH cte AS
    (
       SELECT *
       FROM   TableName
       WHERE  [PostalCode] <>
                      CONVERT(NVARCHAR(50), CONVERT(VARCHAR(50), [PostalCode]))
    )
    UPDATE cte
    SET    cte.[PostalCode] = REPLACE(CONVERT(VARCHAR(50), [PostalCode]), '?', '');
    

    Tenga en cuenta que la consulta anterior no está diseñada para funcionar de manera eficiente si la tabla tiene millones de filas. En ese momento, tendría que manejarse en conjuntos más pequeños a través de un bucle.

Como referencia, aquí está el artículo de wikipedia para Código postal , que actualmente establece que los únicos caracteres que se usan son:

Y con respecto al tamaño máximo del campo, aquí está la Wikipedia Lista de códigos postales