Есть процедура для записи 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;
→ Ссылка