【问题标题】:SQL Server. Separate XML file with FOR XML PATH(...) into a single XML fileSQL 服务器。使用 FOR XML PATH(...) 将 XML 文件分隔为单个 XML 文件
【发布时间】:2018-03-20 15:25:38
【问题描述】:

我一直在阅读这篇文章: https://www.red-gate.com/simple-talk/sql/database-administration/manipulating-xml-data-in-sql-server/

我找到了我需要的东西,但我的情况的唯一区别是我需要使用FOR XML PATH(...) 而不是 ROOT(...) 而不是AUTO 模式。

我有一个使用表格列作为元素的 XML 文件。我要解决的问题:

1) 如何在 select 语句中为每条记录生成一个 XML 文件;

2) 将每个 xml 文件以基于 rowId 的唯一名称保存在共享服务器上

注意:每个 XML 行的硬编码值不是一个选项,因为我的输出包含数千行。

这里的问题是Cursor语句中不允许使用FOR XML和XML数据类型。

CREATE TABLE #T1 
(
    ID INT NOT NULL,
    LName NVARCHAR(30) NULL,
    FName NVARCHAR(30) NULL,
    Comments NVARCHAR(MAX) NULL
);

GO

INSERT INTO #T1 (ID, LName, FName, Comments)
    VALUES
        (1, 'JONOTHAN', 'SMITH', 'is the best friend ever'),
        (2, 'ROGER', 'SHU`LTS', 'is the boss!'),
        (3, 'Jeremy', 'Deimer', 'is the a good drama actor'),
        (4, 'Alexandra', 'Norusis', 'is the smart feminist');

GO

SELECT 
    t.ID, 
    t.LName, 
    t.FName, 
    t.Comments
FROM #T1 t
    FOR XML PATH(''), ROOT ('body');

以下是当前输出的 XML 文件格式:

 <body>
  <ID>1</ID>
  <LName>JONOTHAN</LName>
  <FName>SMITH</FName>
  <Comments>is the best friend ever</Comments>
  <ID>2</ID>
  <LName>ROGER</LName>
  <FName>SHU`LTS</FName>
  <Comments>is the boss!</Comments>
  <ID>3</ID>
  <LName>Jeremy</LName>
  <FName>Deimer</FName>
  <Comments>is the a good drama actor</Comments>
  <ID>4</ID>
  <LName>Alexandra</LName>
  <FName>Norusis</FName>
  <Comments>is the smart feminist</Comments>
</body>

以下是所需的输出(基于 ID = 1 的记录)

        <body>
          <ID>1</ID>
          <LName>JONOTHAN</LName>
          <FName>SMITH</FName>
          <Comments>is the best friend ever</Comments>
        <body>

【问题讨论】:

    标签: sql-server xml tsql for-xml-path


    【解决方案1】:

    我认为这就是你需要的:

    DECLARE @tbl TABLE 
    (
        ID INT NOT NULL,
        LName NVARCHAR(30) NULL,
        FName NVARCHAR(30) NULL,
        Comments NVARCHAR(MAX) NULL
    );
    
    INSERT INTO @tbl (ID, LName, FName, Comments)
        VALUES
            (1, 'JONOTHAN', 'SMITH', 'is the best friend ever'),
            (2, 'ROGER', 'SHU`LTS', 'is the boss!'),
            (3, 'Jeremy', 'Deimer', 'is the a good drama actor'),
            (4, 'Alexandra', 'Norusis', 'is the smart feminist');
    

    --将此用于您的CURSOR

    SELECT ID
         ,(SELECT t1.* FOR XML PATH('body'),TYPE) AS TheRowAsXml
    FROM @tbl AS t1 
    

    结果

    ID  TheRowAsXml
    1   <body><ID>1</ID><LName>JONOTHAN</LName><FName>SMITH</FName><Comments>is the best friend ever</Comments></body>
    2   <body><ID>2</ID><LName>ROGER</LName><FName>SHU`LTS</FName><Comments>is the boss!</Comments></body>
    3   <body><ID>3</ID><LName>Jeremy</LName><FName>Deimer</FName><Comments>is the a good drama actor</Comments></body>
    4   <body><ID>4</ID><LName>Alexandra</LName><FName>Norusis</FName><Comments>is the smart feminist</Comments></body>
    

    使用 CURSOR 更新您的示例

    DECLARE @tbl TABLE 
    (
        ID INT NOT NULL,
        LName NVARCHAR(30) NULL,
        FName NVARCHAR(30) NULL,
        Comments NVARCHAR(MAX) NULL
    );
    
    INSERT INTO @tbl (ID, LName, FName, Comments)
        VALUES
            (1, 'JONOTHAN', 'SMITH', 'is the best friend ever'),
            (2, 'ROGER', 'SHU`LTS', 'is the boss!'),
            (3, 'Jeremy', 'Deimer', 'is the a good drama actor'),
            (4, 'Alexandra', 'Norusis', 'is the smart feminist');
    
    DECLARE @ID INT;
    DECLARE @xml XML;
    
    DECLARE @BusinessCursor as CURSOR;
    
    SET @BusinessCursor = CURSOR FOR
    
    SELECT ID
          ,(
         SELECT t1.* 
         FOR XML PATH(''),ROOT('body'),TYPE
         )  AS TheXml
    FROM @tbl AS t1
    
    OPEN @BusinessCursor;
    
    FETCH NEXT FROM @BusinessCursor INTO @ID, @xml;
    
    WHILE @@FETCH_STATUS = 0 
    BEGIN
        --Do something with the values
        PRINT 'ID: ' +  CAST(@ID AS VARCHAR(10));
        PRINT 'XML: ' + CAST(@xml AS NVARCHAR(MAX));
        --Here you can build your BCP command.
        --Use the ID or any other information to build the file's name and save the XML out (use -w -T)
    
        FETCH NEXT FROM @BusinessCursor INTO @ID, @xml;
    END
    
    CLOSE @BusinessCursor;
    DEALLOCATE @BusinessCursor;
    

    【讨论】:

    • @JeroenMostert 谢谢,好收获!有时人们认为复杂:-) 编辑了我的答案...
    • 唯一要指出的是,它确实会产生所需的输出,您实际上需要离开 where 子句;否则 XML 文件将默认将所有行的数据连接到每个 XML 记录中。此外,为了避免 XML 文件中的标记问题,我们需要使用这个 FOR XML PATH(''),ROOT('body'), TYPE
    • 还有Shnugo,我根据您的回答发布了自己的答案。虽然我排除了你的答案。使用 WHERE t1.ID=t2.ID 子句的问题是套管交叉应用类型输出。但是如果我省略它,它会将所有行中的所有数据连接到一个 XML 行中。
    • @enigma6205 您正在使用SELECT * FROM @tbl AS t2。使用SELECT t1.* FOR XML ... 没有FROM 应该就足够了。
    • Shnugo,由于此错误,您的建议不适用于游标:在 CURSOR 语句中不允许使用 FOR XML 子句。
    【解决方案2】:
    SELECT 
        ID, 
        LName, 
        FName, 
        Comments
    FROM #T1
        FOR XML PATH('body');
    

    我认为这是您的预期结果:

    <body>
      <ID>1</ID>
      <LName>JONOTHAN</LName>
      <FName>SMITH</FName>
      <Comments>is the best friend ever</Comments>
    </body>
    <body>
      <ID>2</ID>
      <LName>ROGER</LName>
      <FName>SHU`LTS</FName>
      <Comments>is the boss!</Comments>
    </body>
    <body>
      <ID>3</ID>
      <LName>Jeremy</LName>
      <FName>Deimer</FName>
      <Comments>is the a good drama actor</Comments>
    </body>
    <body>
      <ID>4</ID>
      <LName>Alexandra</LName>
      <FName>Norusis</FName>
      <Comments>is the smart feminist</Comments>
    </body>
    

    【讨论】:

    • McNets,感谢您的回复。但我需要动态地做到这一点。由于我正在生成数千个 XML 文件,因为我的输出包含许多数据行。所以我不能手动硬核它
    【解决方案3】:
    DECLARE @tbl TABLE 
    (
        ID INT NOT NULL,
        LName NVARCHAR(30) NULL,
        FName NVARCHAR(30) NULL,
        Comments NVARCHAR(MAX) NULL
    );
    
    INSERT INTO @tbl (ID, LName, FName, Comments)
        VALUES
            (1, 'JONOTHAN', 'SMITH', 'is the best friend ever'),
            (2, 'ROGER', 'SHU`LTS', 'is the boss!'),
            (3, 'Jeremy', 'Deimer', 'is the a good drama actor'),
            (4, 'Alexandra', 'Norusis', 'is the smart feminist');
    
    
    DECLARE @xml XML
    
    DECLARE @BusinessCursor as CURSOR;
    
    SET @BusinessCursor = CURSOR FOR
    
    SELECT
    -- ID
       --  ,
       (
         SELECT * 
         FROM @tbl AS t2 
    --   WHERE t1.ID=t2.ID 
         FOR XML PATH(''),ROOT('body'),TYPE
         ) AS TheRowAsXml
    FROM @tbl AS t1
    
    OPEN @BusinessCursor;
    
    FETCH NEXT FROM @BusinessCursor INTO @xml;
    
    WHILE @@FETCH_STATUS = 0 
    
    BEGIN
      SELECT ( 
         SELECT *
         FROM @tbl AS t2 
         WHERE t1.ID=t2.ID 
         FOR XML PATH(''),ROOT('body'), TYPE
         ) AS TheRowAsXml
    FROM @tbl AS t1
    FETCH NEXT FROM @BusinessCursor INTO @xml;
    END
    
    CLOSE @BusinessCursor;
    DEALLOCATE @BusinessCursor;
    

    【讨论】:

    • 我必须承认,我不知道你的 CURSOR 试图达到什么目的......我认为 SELECT 不应该在那里重复......
    • 有select语句。它在结果集中产生了多行。我需要从结果集中为每行生成一个 XML 文件。第二部分是用自己唯一的名称分别保存每个生成的 XML 文件。所以我的回答(在你的帮助下)做得很好。但它产生重复的、“交叉应用”之类的结果的问题。以及 dot help 提出的建议解决方案。
    • 请看我对你上面回答的评论。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    相关资源
    最近更新 更多