Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Преобразуване на Unicode в Non-Unicode

Тук трябва да отбележите няколко неща:

  1. Ако искате да видите точно кой знак има, можете да конвертирате стойността в VARBINARY което ще ви даде шестнадесетичната / двоичната стойност на всички знаци в низа и няма концепция за "скрити" знаци в шестнадесетичен:

    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];
    

    Връща:

    NVarCharValue   VarCharValue   RTrimmedVarCharValue   VarBinaryValue
    053000          053000?        053000?                0x3000350033003000300030000820
    

    NVARCHAR данните се съхраняват като UTF-16, който работи в 2-байтови набори. Разглеждайки последните 4 шестнадесетични цифри, за да видим какъв е скрития 2-байтов набор, виждаме "0820". Тъй като Windows и SQL Server са UTF-16 Little Endian (т.е. UTF-16LE), байтовете са в обратен ред. Обръщане на последните 2 байта -- 08 и 20 -- получаваме "2008", което е "Интервалът за препинателни знаци", който добавихме чрез NCHAR(0x2008) .

    Също така имайте предвид, че RTRIM тук изобщо не помогна.

  2. Опростено, можете просто да замените въпросителните знаци с нищо:

    SELECT REPLACE(CONVERT(VARCHAR(20), [PostalCode]), '?', '');
    
  3. По-важното е, че трябва да конвертирате [PostalCode] поле към VARCHAR така че да не съхранява тези знаци. Нито една страна не използва букви, които не са представени в набора от символи ASCII и които не са валидни за типа данни VARCHAR, поне доколкото съм чел (вижте долния раздел за справки). Всъщност това, което е позволено, е доста малко подмножество от ASCII, което означава, че можете лесно да филтрирате по пътя (или просто да направите същото REPLACE както е показано по-горе при вмъкване или актуализиране):

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

    Не забравяйте да проверите текущия NULL / NOT NULL настройка за колоната и я направете същата в оператора ALTER по-горе, в противен случай тя може да бъде променена, тъй като по подразбиране е NULL ако не е посочено.

  4. Ако не можете да промените схемата на таблицата и трябва да правите периодично "почистване" на лошите данни, можете да изпълните следното:

    ;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]), '?', '');
    

    Моля, имайте предвид, че горната заявка не е предназначена да работи ефективно, ако таблицата има милиони редове. В този момент ще трябва да се обработва в по-малки комплекти чрез цикъл.

За справка, ето статията в wikipedia за Пощенски код , който в момента гласи, че единствените използвани някога знаци са:

А относно максималния размер на полето, ето Списък с пощенски кодове в Уикипедия



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. TSQL валидиране на имейл (без регулярен израз)

  2. Използване на IF EXISTS с CTE

  3. Как да създадете таблица в SQL Server с помощта на заявка

  4. Функцията Contains() се проваля с низове от числа?

  5. как да разберете състоянието на изпълняваните в момента задачи