Генерация XML-файла из SQL Server 2008 - PullRequest
7 голосов
/ 26 ноября 2009

Я работаю над приложением, в котором мне нужно получить ответ SQL в виде XML в файл XML (и сохранить его в каком-то физическом месте, скажем, c: \ xyz.xml ).

Я могу генерировать XML-контент, используя положения, доступные в SQL Server, как показано ниже.

 SELECT * FROM @Table FOR XML AUTO, ELEMENTS

где: @Table - табличная переменная.

Я хочу знать, как я могу сохранить выходные данные запроса в файл XML с самого SQL Server.

Ответы [ 8 ]

8 голосов
/ 17 октября 2012

Есть еще один вариант - используйте sqlcmd tool .

  1. Добавьте :XML ON в качестве первой строки в вашем файле SQL (назовем это input.sql )
  2. Команда, подобная этой, сделает свое дело:
sqlcmd -S <your-server> -i input.sql -o output.xml
5 голосов
/ 26 ноября 2009

Вы не можете записывать в файловую систему с самого SQL Server. По крайней мере, не так легко. Есть три варианта:

  • используйте xp_cmdshell. Я настоятельно советую против этого. По умолчанию xp_cmdshell отключено в целях безопасности, и включение его только для этой операции открывает путь к большой дыре в безопасности вашей системы.

  • используйте FileSystemObject и процедуры автоматизации OLE sp_OACreate / sp_OAMethod. См. Чтение и запись файлов в SQL Server с использованием T-SQL . Это, хотя и незначительно лучше, чем опция xp_cmdshell, но не намного лучше рассказывает о безопасности. Единственная причина, по которой он лучше xp_cmdshell, заключается в том, что хакеры знают об этом гораздо меньше. Но опция OLE Automation в SQL Server также по умолчанию отключена, и включение этой опции выявляет те же проблемы безопасности, что и xp_cmdshell.

  • использовать процедуру CLR. Это было бы моей рекомендацией. Создайте сборку с цифровой подписью, используйте подпись сборки, чтобы разрешить, с помощью подписи кода Transact-SQL, EXTERNAL ACCESS, затем используйте процедуру CLR для записи XML в файловую систему. Хотя это значительно сложнее, чем простые опции xp_cmdshell или OLE Automation, он является наиболее управляемым и детализированным с точки зрения безопасности и самым простым в обслуживании и использовании (это код .Net в отличие от сценариев оболочки). К сожалению, по умолчанию опция clr также отключена на сервере и должна быть включена.

5 голосов
/ 26 ноября 2009

Вам необходимо использовать xp_cmdshell и утилиту bcp следующим образом

EXEC xp_cmdshell 'bcp "SELECT * FROM @Table FOR XML AUTO, ELEMENTS" queryout "C:\table.xml" -c -T'

Напишите мне в комментариях, если у вас есть какие-либо вопросы или вы хотите узнать больше о том, как это работает.

0 голосов
/ 27 марта 2016

Я сделал этот SP, чтобы я мог легко извлечь данные из таблицы базы данных или временной таблицы в файл XML в файловой системе. Поддерживает предложение where.

CREATE PROCEDURE dbo.ExportToXMLFile
      @TableName varchar(1000)
    , @Where varchar(2000)=''
    , @TicketNumber varchar(500)
    , @debug bit=0
as
/*
    Date:2016-03-27
    Author: BojNed
    Purpose: Exports data from table to XML file on filesystem. 
    @TableName = name of table to export. 
    @Where = optitional, to set @Where Clause. DO NOT ENTER WHERE at beggining of the string 
    @TicketNumber = To save to folder on filesystem
    @Debug = Optitional. To debug this SP.

    Examples:
    EXEC dbo.ExportToXMLFile '#tt','columnX=2','221',0
    EXEC dbo.ExportToXMLFile '[Production].[Product]','','252',1
    EXEC dbo.ExportToXMLFile '[dbo].[DatabaseLog]','ColumnZ=55','351',0
    EXEC dbo.ExportToXMLFile '[dbo].[DatabaseLog]','','7865',1
*/
begin 

    if @debug=0
        SET NOCOUNT ON

    declare @SQL nvarchar(max)
    declare @IsTempTable bit
    declare @NewTableName varchar(1000)
    declare @Xml as XML

    if (isnull(@TicketNumber,''))=''
    begin
        RAISERROR('No ticket number defined',16,1,1)
        RETURN
    END

    --check if table is tmp or variable
    if (SELECT SUBSTRING(@TableName,1,1))='#' or (SELECT SUBSTRING(@TableName,1,1))='@'
    BEGIN
        if @debug=1
            PRINT 'Source is TMP table'
        set @NewTableName='TMPTBL_'+@TableName
    END
    ELSE
    BEGIN
        if @debug=1
            PRINT 'Source is db table'
        set @NewTableName=replace(@TableName,'.','_')
    END

        --RemoveSpecialChars
        declare @KeepValues varchar(1000)
        set @KeepValues = '%[^a-z^0-9^_]%'
        WHILE PATINDEX(@KeepValues,@NewTableName)>0
        set @NewTableName = STUFF(@NewTableName, PATINDEX(@KeepValues,@NewTableName),1,'')

    if @debug=1
        PRINT 'Node name for XML Header and filename: '+@NewTableName

    if ISNULL(@Where,'')=''
    BEGIN
        set @SQL= 'SELECT * FROM '+ @TableName+' FOR XML PATH, ROOT ('''+@NewTableName+'''), ELEMENTS'
        if @debug=1
            PRINT 'NO Where condition'
    END
    ELSE
    BEGIN
        set @SQL= 'SELECT * FROM '+ @TableName+' WHERE '+@Where+ ' FOR XML PATH, ROOT ('''+@NewTableName+'''), ELEMENTS'
        if @debug=1
            PRINT 'With Where condition'
    END

    --Get XML to tbl
    if ISNULL(OBJECT_ID ('tempdb..##TXML'),0)>0
    DROP TABLE ##TXML

    CREATE TABLE ##TXML (XMLText XML)

    set @SQL =  ' insert into ##TXML select ('+@SQL+')'

    --parse query
    declare @testsql nvarchar(max)
    declare @result int
    set @testsql = N'set parseonly on; ' + @sql
    exec @result = sp_executesql @testsql

    -- If it worked, execute it
    if @result = 0
        begin
            if @debug=1
                PRINT 'Query OK: '+ @SQL
            exec sp_executesql @sql
        end
    else 
    BEGIN
        DECLARE @msg varchar(2000)
        set @msg ='Parsing Error on query: ' + @SQL
        RAISERROR (@msg,16,1,1)
        RETURN
    END

    DECLARE @Tbl TABLE (id int identity(1,1), Dir varchar(256))

    --check if dir exsists
    INSERT into @Tbl
    EXEC master.dbo.xp_subdirs 'C:\DataCorrectionBackup\'


    if (SELECT Count(*) from @Tbl WHERE Dir=@TicketNumber)=0
    BEGIN
        --create new dir
        DECLARE @t varchar(500)
        set @t ='C:\DataCorrectionBackup\'+@TicketNumber

        EXEC master.sys.xp_create_subdir @t
    END

    declare @bcp varchar(500)
    declare @Filename VARCHAR(255)

    set @Filename =convert(varchar(100),GETDATE(),112)+'_'+replace(convert(varchar(100),GETDATE(),114),':','')+'_'+@NewTableName+'.xml'

    set @bcp = 'bcp "SELECT XMLText from ##TXML" queryout C:\DataCorrectionBackup\'+@TicketNumber+'\'+@Filename+' -w -T -S'+ @@servername

    --save file
    if @debug=0
        EXEC xp_cmdshell @bcp, NO_OUTPUT
    ELSE 
    BEGIN
        EXEC xp_cmdshell @bcp
        PRINT @bcp
    END

    DROP table ##TXML

end

go
0 голосов
/ 18 октября 2014

Если ваш xml вывод относительно небольшой (<4000 символов), то вы можете использовать этот SP: </p>

IF EXISTS (SELECT TOP 1 1 FROM sys.objects WHERE object_id = OBJECT_ID('dbo.USP_WRITE_UNICODE_STRING_TO_FILE') AND type = 'P')
BEGIN
    DROP PROCEDURE dbo.USP_WRITE_UNICODE_STRING_TO_FILE
END
GO

-- =============================================
-- Description: Writes the specified Unicode string to the specified file.
-- Permissions: This stored procedure uses xp_cmdshell which is disabled by default. To enable it:
--              1. In Management Studio connect to a component of SQL Server.
--              2. In Object Explorer, right-click the server, and then click Facets.
--              3. In the View Facets dialog box, expand the Facet list, and select the Surface Area Configuration.
--              4. In the Facet properties area, select XPCmdShellEnabled property and set its value to True.
--              5. Click OK.
-- Example:     EXEC dbo.USP_WRITE_UNICODE_STRING_TO_FILE'<root> <a b="c" /> </root>', 'C:\Test.xml', 1;
-- =============================================
CREATE PROCEDURE dbo.USP_WRITE_UNICODE_STRING_TO_FILE
(
    @Str            NVARCHAR(4000),
    @XmlFilePath    NVARCHAR(256),
    @Debug          BIT = 0
)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @Str1 NVARCHAR(MAX),
            @Cmd NVARCHAR(4000),
            @MaxLen int = 4000;

    --see: http://technet.microsoft.com/en-us/library/bb490897.aspx
    SET @Str1 = REPLACE(REPLACE(REPLACE(@Str, '>', '^>'), '<', '^<'), '"', '^"');
    -- '>' Writes the command output to a file 
    SET @Str1 =N'ECHO ' + @Str1  + N'>"'+ @XmlFilePath + N'"';
    IF @Debug = 1
    BEGIN
        DECLARE @Msg varchar(128) = 'The total lenght is ' + CAST(LEN(@Str1) AS VARCHAR(10)) + ' characters.'
        PRINT @Msg;
        PRINT @Str1;
    END

    IF (LEN(@Str1) > @MaxLen)
        RAISERROR  ('The input string is too long', 11, 0);
    ELSE
        SET @Cmd = CAST (@Str1 AS NVARCHAR(4000));

    EXEC master..xp_cmdshell @Cmd, NO_OUTPUT;           
END
GO

--Test 1
DECLARE @Str NVARCHAR(4000);
DECLARE @Xml xml = '<root> <a b="c" /> </root>';
SET @Str = CAST (@Xml AS NVARCHAR(4000));
EXEC dbo.USP_WRITE_UNICODE_STRING_TO_FILE @Str, 'C:\Test.xml', 1;
GO
--Test 2
DECLARE @Str NVARCHAR(4000);
SET @Str = REPLICATE('a', 4000);
EXEC dbo.USP_WRITE_UNICODE_STRING_TO_FILE @Str, 'C:\Test.xml', 1;
GO

Если вы не работаете с Unicode, вы можете создать еще один SP: USP_WRITE_NON_UNICODE_STRING_TO_FILE, который будет очень похож на предыдущий со следующими изменениями:

    CREATE PROCEDURE dbo.USP_WRITE_NON_UNICODE_STRING_TO_FILE
    (
        @Str            VARCHAR(8000),
        @XmlFilePath    NVARCHAR(256),
        @Debug          BIT = 0
    )
    AS
    BEGIN
        SET NOCOUNT ON;

        DECLARE @Str1 VARCHAR(MAX),
                @Cmd VARCHAR(8000),
                @MaxLen int = 8000;
        ...
        SET @Cmd = CAST (@Str1 AS VARCHAR(8000));

Этот SP позволяет использовать в два раза длиннее строку ввода (<8000 символов). </p>

Если ваш XML длиннее 8000, но меньше 1 МБ, вы можете использовать утилиту sqlcmd без команды: XML ON. Это значительно упрощает использование утилиты, поскольку вам не нужен отдельный файл input_file с включенной командой XML ON. Вот пример:

DECLARE @Cmd NVARCHAR(4000);
SET @Cmd = N'sqlcmd -S ' + @@SERVERNAME + N' -d ' + DB_NAME() + 
N' -Q "SET NOCOUNT ON; DECLARE @Xml xml = ''<root> <a >b</a> </root>''; SELECT CONVERT(NVARCHAR(MAX), @Xml);" -o "C:\Test.xml" -y 0';
PRINT @Cmd;
EXEC master..xp_cmdshell @Cmd, NO_OUTPUT;

Вы также можете использовать SP здесь:

CREATE PROCEDURE dbo.USP_SAMPLE_PROCEDURE
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @Xml xml;
    SET @Xml = (SELECT name, type_desc FROM sys.objects FOR XML PATH('object'), ROOT('sys.objects'));
    SELECT CONVERT(NVARCHAR(MAX), @Xml)
END
GO

DECLARE @Cmd NVARCHAR(4000);
SET @Cmd = N'sqlcmd -S ' + @@SERVERNAME + N' -d ' + DB_NAME() + 
N' -Q "EXEC dbo.USP_SAMPLE_PROCEDURE;" -o "C:\Test.xml" -y 0';
PRINT @Cmd;
EXEC master..xp_cmdshell @Cmd, NO_OUTPUT;
GO

Если ваш XML превышает 1 МБ, вы должны использовать: XML ON команду в отдельном скрипте и указать ее в качестве параметра -i input_file.

0 голосов
/ 08 марта 2013

Простой SQL-метод записи в файл

DECLARE @xml XML = '<MyXML></MyXMl>'
DECLARE @strXML varchar(max) = convert(varchar(max),@XML) 

-- Add white space for readability 
SELECT @strxml = replace(@strxml,'</',char(13) + char(10) + '</')
--- Add Declartives, namespaces and xls 

Create Table dbo.BCP_OUT(contents varchar(max)) 
INSERT INTO dbo.bcp_out(contents)
SELECT Convert(varchar(max),@strXML ) 

EXEC xp_cmdshell N'BCP -S SERVER [database].dbo.bcp_out -T -c -o \\pathto\file.name' 
0 голосов
/ 26 ноября 2009

Вы можете создать функцию CLR, которая создаст файл, встроить его в сервер sql и использовать из хранимой процедуры

Другой способ (я его не проверял) - есть инструмент bcp

bcp "Select * from dbo..table FOR XML RAW" queryout c:\temp\test.xml -Soc-db -Uuser -Ppassword 

Этот пример взят из здесь

0 голосов
/ 26 ноября 2009

Если вы нажмете

ctrl + shift + f

вы выберете «Результаты в файл». Это можно найти в меню «Запрос» в верхней панели Sql Management Studio.

Или вставьте что-то подобное в свой скрипт sql

exec xp_cmdshell 'bcp "select * from suppliers" queryout "c:\suppliers.txt" -S server -T'

См. по этой ссылке . Существует проблема, связанная с тем, является ли это диск приложения или c диска сервера SQL. Веселитесь, разбираясь с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...