Есть процедура для записи XML файла в БД с изменением кодировки из UTF 8 в UTF 16 на MS SQL Server
В чем проблема. Ошибки не выдает выполнение процедуры, но при попытке просмотра таблицы загруженных данных, она просто пустая, есть только сами столбцы. В чем может быть проблема или нужен какой-то другой способ перекодирования в самой процедуре. Да, перекодирование с utf 8 в utf 16 необходимо сделать в самой процедуре перед загрузкой данных в таблицу.
ALTER PROCEDURE [dbo].[LoadStoresFromXML]
@XMLFilePath NVARCHAR(MAX) = 'D:\jobLasmart\virtualpos\stores.xml' -- Укажите путь к файлу
AS
BEGIN
SET NOCOUNT ON;
-- Переменные для работы с файлами
DECLARE @XMLData NVARCHAR(MAX);
DECLARE @FileHandle INT;
DECLARE @TextStream INT;
DECLARE @UTF16Data NVARCHAR(MAX);
-- Читаем содержимое файла в переменную
EXEC sp_OACreate 'Scripting.FileSystemObject', @FileHandle OUTPUT;
EXEC sp_OAMethod @FileHandle, 'OpenTextFile', @TextStream OUTPUT, @XMLFilePath, 1, 0; -- 1 = ForReading, 0 = ASCII
EXEC sp_OAMethod @TextStream, 'ReadAll', @XMLData OUTPUT; -- Читаем весь файл
EXEC sp_OAMethod @TextStream, 'Close', NULL;
EXEC sp_OADestroy @TextStream;
EXEC sp_OADestroy @FileHandle;
-- Преобразовываем данные в кодировку UTF-16
-- Datalength увеличивается в 2 раза, так как в UTF-16 каждый символ занимает 2 байта
SET @UTF16Data = CONVERT(NVARCHAR(MAX), @XMLData COLLATE Latin1_General_BIN);
-- Вставка данных из XML в таблицу Stores
DECLARE @XML XML = CAST(@UTF16Data AS XML);
INSERT INTO dbo.Stores (id, open_time, close_time, name, address, phone, headquerter_id, created_date, created_by,
last_update_date, last_update_by, flag24hours, lat, lon, minusale, location_id,
external_id, show_in_shop, organisation_id, vat_mandatory, manager_user_id, [primary])
SELECT
Store.value('(id)[1]', 'int') AS id,
Store.value('(open_time)[1]', 'time(7)') AS open_time,
Store.value('(close_time)[1]', 'time(7)') AS close_time,
Store.value('(name)[1]', 'nvarchar(255)') AS name,
Store.value('(address)[1]', 'nvarchar(255)') AS address,
Store.value('(phone)[1]', 'nvarchar(50)') AS phone,
Store.value('(headquerter_id)[1]', 'int') AS headquerter_id,
Store.value('(created_date)[1]', 'datetime') AS created_date,
Store.value('(created_by)[1]', 'int') AS created_by,
Store.value('(last_update_date)[1]', 'datetime') AS last_update_date,
Store.value('(last_update_by)[1]', 'int') AS last_update_by,
Store.value('(flag24hours)[1]', 'bit') AS flag24hours,
Store.value('(lat)[1]', 'decimal(9, 6)') AS lat,
Store.value('(lon)[1]', 'decimal(9, 6)') AS lon,
Store.value('(minusale)[1]', 'int') AS minusale,
Store.value('(location_id)[1]', 'int') AS location_id,
Store.value('(external_id)[1]', 'int') AS external_id,
Store.value('(show_in_shop)[1]', 'bit') AS show_in_shop,
Store.value('(organisation_id)[1]', 'int') AS organisation_id,
Store.value('(vat_mandatory)[1]', 'bit') AS vat_mandatory,
Store.value('(manager_user_id)[1]', 'int') AS manager_user_id,
Store.value('(primary)[1]', 'bit') AS [primary]
FROM @XML.nodes('/Stores/Store') AS Store(Store);
END;```
Ответы (1 шт):
Автор решения: Yitzhak Khabinsky
→ Ссылка
Попробуйте следующее, гораздо более простое и надежное решение на T-SQL.
Также обратите внимание на text()
, добавленный в целях повышения производительности к каждому методу .value()
XQuery.
Образец XML-файла не предоставлен. Поэтому может потребоваться добавить пространства имен XML.
SQL
ALTER PROCEDURE [dbo].[LoadStoresFromXML]
@XMLFilePath NVARCHAR(MAX) = 'D:\jobLasmart\virtualpos\stores.xml' -- Укажите путь к файлу
AS
BEGIN
SET NOCOUNT ON;
-- Шаг №1: загрузить XML-файл в однострочную таблицу базы данных
DECLARE @tbl TABLE (XMLColumn XML);
DECLARE @sql NVARCHAR(MAX) =
N'SELECT BulkColumn
FROM Openrowset(Bulk N' + QUOTENAME(@XMLFilePath, NCHAR(39)) + ', Single_Blob) x;';
INSERT INTO @tbl (XMLColumn)
EXEC sys.sp_executesql @sql;
-- Шаг №2: Вставка данных из XML в таблицу Stores
INSERT INTO dbo.Stores (id, open_time, close_time, name, address, phone, headquerter_id, created_date, created_by,
last_update_date, last_update_by, flag24hours, lat, lon, minusale, location_id,
external_id, show_in_shop, organisation_id, vat_mandatory, manager_user_id, [primary])
SELECT
Store.value('(id/text())[1]', 'int') AS id,
Store.value('(open_time/text())[1]', 'time(7)') AS open_time,
Store.value('(close_time/text())[1]', 'time(7)') AS close_time,
Store.value('(name/text())[1]', 'nvarchar(255)') AS name,
Store.value('(address/text())[1]', 'nvarchar(255)') AS address,
Store.value('(phone/text())[1]', 'nvarchar(50)') AS phone,
Store.value('(headquerter_id/text())[1]', 'int') AS headquerter_id,
Store.value('(created_date/text())[1]', 'datetime') AS created_date,
Store.value('(created_by/text())[1]', 'int') AS created_by,
Store.value('(last_update_date)[1]', 'datetime') AS last_update_date,
Store.value('(last_update_by/text())[1]', 'int') AS last_update_by,
Store.value('(flag24hours/text())[1]', 'bit') AS flag24hours,
Store.value('(lat/text())[1]', 'decimal(9, 6)') AS lat,
Store.value('(lon/text())[1]', 'decimal(9, 6)') AS lon,
Store.value('(minusale/text())[1]', 'int') AS minusale,
Store.value('(location_id/text())[1]', 'int') AS location_id,
Store.value('(external_id/text())[1]', 'int') AS external_id,
Store.value('(show_in_shop/text())[1]', 'bit') AS show_in_shop,
Store.value('(organisation_id/text())[1]', 'int') AS organisation_id,
Store.value('(vat_mandatory/text())[1]', 'bit') AS vat_mandatory,
Store.value('(manager_user_id/text())[1]', 'int') AS manager_user_id,
Store.value('(primary/text())[1]', 'bit') AS [primary]
FROM @tbl
CROSS APPLY XMLColumn.nodes('/Stores/Store') AS Store(Store);
END;