【问题标题】:Export XML column rows from SQL table into individual files将 SQL 表中的 XML 列行导出到单个文件中
【发布时间】:2017-02-13 20:12:31
【问题描述】:

我有一个名为 REFERENCES 的表,其中包含几十万行 XML,我想将它们提取为单独的 XML 文件。

大致格式如下:

+--------------+------------------+
| REFERENCE_ID | REFERENCE_XML    |
+--------------+------------------+
| 1            | <xml>...</xml>   |
| 2            | <xml>...</xml>   |
| 3            | <xml>...</xml>   |
| 4            | <xml>...</xml>   |
| ...          | <xml>...</xml>   |
| 70000        | <xml>...</xml>   |
+--------------+------------------+

我想遍历每一行并批量导出每个REFERENCE_XML 列并将其命名为REFERENCE_ID

我的输出文件夹集如下所示:

C:\References\1.xml
C:\References\2.xml
C:\References\3.xml
C:\References\4.xml
C:\References\...
C:\References\70000.xml

我能够找到一个粗略的查询来执行单个静态行的操作,但是我很难找出创建WHILE 循环或CURSOR 的最佳方法。如何使文件名和 WHERE 子句动态循环以遍历 REFERENCES 表中的每一行并将所有 XML 导出为单个文件?

DECLARE @fileName VARCHAR(MAX)
DECLARE @sqlStr VARCHAR(MAX)
DECLARE @sqlCmd VARCHAR(MAX)

SET @fileName = 'C:\References\1.xml' -- I need the integer value to be dynamic per row.
SET @sqlStr = SELECT REFERENCE_XML FROM REFERENCE_DB.dbo.REFERENCES WHERE REFERENCE_ID = 1'  -- I need the REFERENCE_ID to be dynamic per row.
SET @sqlCmd = 'bcp "' + @sqlStr + '" queryout ' + @fileName + ' -w -T'

EXEC xp_cmdshell @sqlCmd

【问题讨论】:

    标签: sql sql-server xml tsql


    【解决方案1】:

    您可以在启动CURSOR 时直接使用ROW_NUMBER() 创建一个流水号。这似乎比在任何迭代中调用完整的SELECT 更容易。

    编辑:我要禁食。您想使用您的ReferenceID 作为号码。只需在不使用ROW_NUMBER() 的情况下采用相同的方式,并在每次迭代时将 ReferenceID 读入@Nr

    Declare @YourTable table (ID int,SomeXml xml);
    Insert Into @YourTable values
     (100,'<root><test a="1"/></root>')
    ,(200,'<root><test a="2"/></root>')
    ,(300,'<root><test a="3"/></root>');
    
    DECLARE @Nr BIGINT,@ID INT,@SomeXml XML;
    DECLARE @fileName VARCHAR(MAX)
    DECLARE @sqlStr VARCHAR(MAX)
    DECLARE @sqlCmd VARCHAR(MAX)
    
    DECLARE cur CURSOR FOR SELECT ROW_NUMBER() OVER(ORDER BY ID) AS Nr,ID,SomeXml FROM @YourTable ;
    OPEN cur;
    
    FETCH NEXT FROM cur INTO @Nr,@ID,@SomeXml;   
    
    WHILE @@FETCH_STATUS = 0   
    BEGIN   
    
        SET @fileName = 'C:\YourPath\' + CAST(@Nr AS VARCHAR(100)) + '.xml' ;
        SET @sqlStr = 'SELECT ''' + CAST(@SomeXml AS NVARCHAR(MAX)) + '''';
        SET @sqlCmd = 'bcp "' + @sqlStr + '" queryout ' + @fileName + ' -w -T';
    
        PRINT @sqlCmd;
        --EXEC xp_cmdshell @sqlCmd
    
        FETCH NEXT FROM cur INTO @Nr,@ID,@SomeXml;    
    END   
    
    CLOSE cur;   
    DEALLOCATE cur;
    

    这是打印出来的:

    bcp "SELECT '<root><test a="1"/></root>'" queryout C:\DVP\1.xml -w -T
    bcp "SELECT '<root><test a="2"/></root>'" queryout C:\DVP\2.xml -w -T
    bcp "SELECT '<root><test a="3"/></root>'" queryout C:\DVP\3.xml -w -T
    

    【讨论】:

    • 通过一些修改(特别是对@sqlStr 行),我能够成功地让它工作。我发现没有必要将 XML 转换为 NVARCHAR。 bcp 能够毫无问题地处理 XML。谢谢!
    • 很遗憾 xp_cmdshell 不接受 (n)varchar(MAX),最大值为 nvarchar(4000)/varchar(8000)。 xml 较长,会被截断,结果无效。必须使用全局临时表 (##),因为 bcp 使用不同的连接,所以“普通”临时表不起作用。我尝试使用带有表变量的 bcp 作为解决方法,但它也不适用于 bcp。
    【解决方案2】:

    我会这样做:

    DECLARE @fileName VARCHAR(MAX)
    DECLARE @sqlStr VARCHAR(MAX)
    DECLARE @sqlCmd VARCHAR(MAX)
    DECLARE @id int
    DECLARE myCursor CURSOR FOR
        SELECT REFERENCE_ID FROM REFERENCE_DB.dbo.REFERENCES
    OPEN myCursor
    FETCH NEXT FROM myCursor
    INTO @id
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @fileName = 'C:\References\' + @id + '.xml'
        SET @sqlStr = SELECT REFERENCE_XML FROM REFERENCE_DB.dbo.REFERENCES WHERE REFERENCE_ID = ' + @id
        SET @sqlCmd = 'bcp "' + @sqlStr + '" queryout ' + @fileName + ' -w -T'
    
        EXEC xp_cmdshell @sqlCmd
    END
    CLOSE myCursor;
    DEALLOCATE myCursor;
    

    【讨论】:

    • 这个...WHERE REFERENCE_ID = ' + @id 没有演员表就不能工作,因为@id 被声明为INT
    猜你喜欢
    • 1970-01-01
    • 2017-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-19
    相关资源
    最近更新 更多