ОБНОВЛЕНИЕ: я только изучаю что-то новое, что - хм - здорово: -)
Попробуйте эту функцию
CREATE FUNCTION dbo.Convert_utf8(@utf8 VARBINARY(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE @rslt NVARCHAR(MAX);
SELECT @rslt=
CAST(
--'<?xml version="1.0" encoding="UTF-8"?><![CDATA['
0x3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E3C215B43444154415B
--the content goes within CDATA
+ @utf8
--']]>'
+ 0x5D5D3E
AS XML).value('.', 'nvarchar(max)');
RETURN @rslt;
END
GO
И назовите это так
SELECT *
,dbo.Convert_utf8(CAST(t.body AS XML).value('.','varbinary(max)'))
FROM @t t;
Результат
DALLAS, TX – May 7, 2019 – Covey & Park Energy Holdings LLC (“Covey Park”
GSerg, большое спасибо! за ответ ниже. Я попытался и упростил это, чтобы работать в UDF.
Похоже, что приведение varbinary(max)
к XML полностью выполнено в среде CLR, где учитывается объявление кодировки XML. Похоже, это работает и с другими кодировками, но у меня сейчас нет времени, чтобы проверить это в общем.
Теперь остальная часть ответа
Поскольку он содержит некоторые сведения о строковом кодировании, которые, возможно, стоит прочитать.
Я немного упростил ваш код:
declare @t table ( [body] nvarchar(max) )
insert into @t(body)
select 'REFMTEFTLCBUWCDigJMgTWF5IDcsIDIwMTkg4oCTIENvdmV5ICYgUGFyayBFbmVyZ3kgSG9sZGluZ3MgTExDICjigJxDb3ZleSBQYXJr4oCdIA==';
SELECT CAST(t.body AS XML).value('.','varbinary(max)')
,CAST(CAST(t.body AS XML).value('.','varbinary(max)') AS VARCHAR(MAX))
FROM @t t;
Вы увидите этот результат
0x44414C4C41532C20545820E28093204D617920372C203230313920E2809320436F7665792026205061726B20456E6572677920486F6C64696E6773204C4C432028E2809C436F766579205061726BE2809D20
DALLAS, TX – May 7, 2019 – Covey & Park Energy Holdings LLC (“Covey Parkâ€
Я сделаю первые символы более удобными для чтения
0x44414C4C41532C20545820E28093
D A L L A S , T X â € “
0x44
- это D
, вдвое больше 0x4C
- удвоенное LL
, и после пробела 0x20
мы получаем E28093
. Это 3-байтовая кодированная точка для en dash . SQL-сервер не поможет вам в этом ... Он будет интерпретировать это как 3 символа по 1 байту каждый ...
Боюсь, тебе не повезло ...
SQL-сервер не поддерживает utf-8
строки. BCP / BULK
имеет ограниченную поддержку для включения ввода из файловой системы, но строка в T-SQL
должна быть одной из двух поддерживаемых опций:
(var)char
, то есть расширенный ASCII . Он строго один байт на символ и будет нуждаться в сопоставлении, чтобы иметь дело с ограниченным набором иностранных символов.
n(var)char
, то есть UCS-2 (очень похоже на UTF-16
). Он строго два байта на символ и будет кодировать (почти) любой известный символ по цене удвоенного размера в памяти.
UTF-8
совместим с (var)char
, если мы придерживаемся обычного латинского и однобайтовых кодов . Но любой код ASCII выше 127 приведет к проблемам (может работать с правильным сопоставлением). Но - это ваш случай здесь - ваша строка использует многобайтовых кодовых точек . UTF-8
будет кодировать множество символов двумя или более байтами (до 4!) Для одного символа.
Что вы можете сделать
Вам придется использовать какой-нибудь двигатель, способный справиться с UTF-8
- CLR-функция
- Экспорт в файл и повторный импорт с использованием ограниченной поддержки (требуется версия v2014 SP2 или выше)
- Используйте внешний инструмент (PowerShell, C #, любой язык программирования, который вы знаете)
И - спасибо @GSerg - еще два варианта:
- Ждите v2019. Будет специальных параметров сортировки , допускающих встроенную поддержку
utf-8
в T-SQL-строках
- Этот ответ предоставляет UDF, который может преобразовать UTF8 в NVARCHAR. Это не будет быстро, но работает.
Общее замечание
База данных может хранить данные хранения просто , как , или рабочие данные, которые вы хотите использовать тем или иным способом. Хранение картинки как VARBINARY(MAX)
- это просто кусок битов. Вы не пытаетесь использовать SQL-Server для распознавания изображений.
То же самое с текстовыми данными. Если вы просто храните кусок текста, не имеет значения, как вы это сделаете. Но если вы хотите использовать этот текст для фильтрации, поиска или если вы хотите использовать SQL-Server для отображения этого текста, вы должны подумать о формате и потребностях в производительности.
Кодирование с переменной длиной байта не допускает простого SUBSTRING('blahblah',2,3)
. С фиксированной длиной движок может просто взять строку в виде массива, перейти ко второму индексу и выбрать следующие три символа. Но с переменными байтами движок должен будет вычислить индекс, проверив все символы раньше, если может быть какая-либо многобайтовая кодовая точка. Это очень сильно замедлит многие строковые методы ...
Лучше всего было не хранить данные в формате, SQL-сервер не может обработать (хорошо) ...