Я пытаюсь создать хранимую процедуру в SQL Server 2016, которая преобразует XML, который ранее был преобразован в Varbinary
, обратно в XML, но при преобразовании получаю ошибку «Недопустимый символ XML». Я нашел обходной путь, который, кажется, работает, но я не могу понять, почему он работает, и мне неудобно.
Хранимая процедура берет данные, которые были преобразованы в двоичные данные в службах SSIS и вставляются в столбец varbinary(MAX)
в таблице, и выполняет простую операцию.
CAST(Column AS XML)
Он работал нормально в течение долгого времени, и я начал замечать проблему только тогда, когда первоначальный XML начал содержать символ ® (зарегистрированный товарный знак).
Теперь, когда я пытаюсь преобразовать двоичный файл в XML, я получаю эту ошибку
Сообщение 9420, уровень 16, состояние 1, строка 23
Анализ XML: строка 1, символ 7, недопустимый символ xml
Однако если я сначала преобразую двоичный файл в varchar(MAX)
, а затем преобразую его в XML, все будет работать нормально. Я не понимаю, что происходит, когда я выполняю этот промежуточный CAST, который отличается от прямого преобразования в XML. Меня больше всего беспокоит то, что я не хочу добавлять его в учетную запись для этого сценария и в конечном итоге получить непредвиденные последствия.
Тестовый код:
DECLARE @foo VARBINARY(MAX)
DECLARE @bar VARCHAR(MAX)
DECLARE @Nbar NVARCHAR(MAX)
--SELECT Varbinary
SET @foo = CAST( '<Test>®</Test>' AS VARBINARY(MAX))
SELECT @foo AsBinary
--select as binary as varchar
SET @bar = CAST(@foo AS VARCHAR(MAX))
SELECT @bar BinaryAsVarchar -- Correct string output
--select binary as nvarchar
SET @nbar = CAST(@foo AS NVARCHAR(MAX))
SELECT @nbar BinaryAsNvarchar -- Chinese characters
--select binary as XML
SELECT TRY_CAST(@foo AS XML) BinaryAsXML -- ILLEGAL XML character
-- SELECT CONVERT(xml, @obfoo) BinaryAsXML --ILLEGAL XML Character
--select BinaryAsVarcharAsXML
SELECT TRY_CAST(@bar AS XML) BinaryAsVarcharAsXML -- Correct Output
--select BinaryAsNVarcharAsXML
SELECT TRY_CAST(@nbar AS XML) BinaryAsNvarcharAsXML -- Chinese Characters
varchar
означает ASCII или, по крайней мере, текст с однобайтовой кодировкой. ® находится за пределами диапазона 0–127, на который не влияют кодовые страницы. Попробуйте с nvarchar иCAST( N'<Test>®</Test>' as varbinary(max))
.nvarchar
означает UTF16, т.е. два байта, поэтому преобразование из varchar в varbinary в nvarchar не удалось. - person Panagiotis Kanavos   schedule 02.11.2018nvarchar
поля, параметры и строковые литералы. - person Panagiotis Kanavos   schedule 02.11.2018varchar
, столкнулся с проблемами преобразования и вместо того, чтобы использовать правильные сопоставления столбцов или переключиться наnvarchar
, просто скрыл проблему, используяvarbinary
. Это ничего не исправило, просто перенесло проблемы с кодировкой в ридер. Это работало, пока не было нелатинских символов (что также не вызвало бы проблем с varchar). Когда был добавлен первый нелатинский символ, бум, программа чтения не удалась. - person Panagiotis Kanavos   schedule 02.11.2018CAST(CAST( '<Test>®</Test>' AS VARBINARY(MAX)) AS NVARCHAR(MAX))
Не делайте этого. Фундаментальное правило кодировок символов — читать с той кодировкой, которая использовалась для записи. - person Tom Blodget   schedule 03.11.2018Description: "Unicode data is odd byte size for column 11. Should be even byte size.".
Из того, что я прочитал, вы можете решить эту проблему, явно указав четную длину строки, но тогда SSIS ограничивает вас до 4000 символов. - person Evan Prickett   schedule 13.11.2018