以 XML 形式检索 SQL 数据的问题

Posted

技术标签:

【中文标题】以 XML 形式检索 SQL 数据的问题【英文标题】:Issue retrieving SQL data as XML 【发布时间】:2019-09-03 20:45:18 【问题描述】:

我遇到了一个 SQL 查询问题,该查询旨在将结果数据作为 XML 返回。这是一个代码转储,向您展示发生了什么:

SQL 查询(注意:表名和列名已编辑)

with resultdata as
(
    SELECT 
    (
        select * from Table1 (nolock)
        where column1 = 99999 and column2 = -1 for xml auto, type
    ) as tabledata 
    UNION ALL
    SELECT
    (   
        select * from Table2 (nolock)
        where column1 = 99999 and column2 = -1 for xml auto, type 
    )
    UNION ALL
    SELECT
    (
        select * from Table3 (nolock)
        where column1 = 99999 and column2 = -1 for xml auto, type
    )
    UNION ALL
    SELECT 
    (
        select * from Table4 (nolock)
        where column1 = 99999 and column2 = -1 for xml auto, type
    )
    UNION ALL
    SELECT 
    (
        select * from Table5 (nolock)
        where column1 = 99999 and column2 = -1 for xml auto, type
    )
    UNION ALL
    SELECT 
    (
        select * from Table6 (nolock)
        where column1 = 99999 and column2 = -1 for xml auto, type
    )
    UNION ALL
    SELECT 
    (
        select * from Table7 (nolock)
        where column1 = 99999 and column2 = -1 for xml auto, type
    )
    UNION ALL
    SELECT 
    (
        select * from Table8 (nolock)
        where column1 = 99999 and column2 = -1 for xml auto, type
    )
)

select * from resultdata result for xml auto, elements

这将返回如下所示的 XML 结果(大部分 XML 已编辑,cmets 是实际数据所在的位置):

<result>
  <tabledata>
    <!--Table1 results-->
  </tabledata>
</result>
<result>
  <tabledata>
    <!--Table2 results-->
  </tabledata>
</result>
<result>
  <tabledata>
    <!--Table3 results-->
  </tabledata>
</result>
<result>
  <tabledata>
    <!--Table4 results-->
  </tabledata>
</result>
<result>
  <tabledata>
    <!--Table5 results-->
  </tabledata>
</result>
<result>
  <tabledata>
    <!--Table6 results-->
  </tabledata>
</result>
<result>
  <tabledata>
   <!--Table7 results-->
  </tabledata>
</result>
<result>
  <tabledata>
    <!--Table8 results-->
  </tabledata>
</result>

显然这是格式错误的 XML,但我似乎无法对其进行修改,以便它以正确的格式为我提供结果,如下所示:

<result>
  <tabledata>
    <!--Table1 results-->
  </tabledata>
  <tabledata>
    <!--Table2 results-->
  </tabledata>
  <tabledata>
    <!--Table3 results-->
  </tabledata>
  <tabledata>
    <!--Table4 results-->
  </tabledata>
  <tabledata>
    <!--Table5 results-->
  </tabledata>
  <tabledata>
    <!--Table6 results-->
  </tabledata>
  <tabledata>
   <!--Table7 results-->
  </tabledata>
  <tabledata>
    <!--Table8 results-->
  </tabledata>
</result>

附带说明,这是对我们现有查询的重写,这就是为什么语法大多是这样的原因。我的一位同事开始对其进行返工并基本上给了我在这里发布的内容,但是我一直在努力尝试使用他的更改使其正常工作。如果我需要废弃它并从头开始,我可以这样做。

另外,作为另一个说明,我希望它看起来像的 XML 必须是这种方式,因为它最终由我无法控制的 XSLT 使用。此查询的旧版本将每个 tabledata 元素作为不同的列名返回,然后在调用它的 C# 代码中进行字符串替换。对此 XML 进行多个字符串替换(可能超过 100k 行)存在性能问题,因此答案是更改查询以按照我们需要的方式返回数据。

【问题讨论】:

从所有子查询中删除“for xml auto, type”会产生错误:“当子查询不使用 EXISTS 引入时,选择列表中只能指定一个表达式。”我还尝试删除 auto 部分并只留下 xml,但这会产生语法错误。 什么在消耗这个 XML?可以将您得到的结果替换为“”的所有实例吗? 它是一个消耗它的 XSLT,但最终这就是我试图避免的字符串替换。当前的实现就是这样做的,而我的老板出于性能原因基本上希望将其删除。 【参考方案1】:

只是另一种选择。这将返回您想要的结果。

Select (select * from Table1 (nolock) where column1 = 99999 and column2 = -1 for XML auto, type, root('tabledata') )
      ,(Select * from Table2 (nolock) where column1 = 99999 and column2 = -1 for XML auto, type, root('tabledata') )
      ,(Select * from Table3 (nolock) where column1 = 99999 and column2 = -1 for XML auto, type, root('tabledata') )
 For XML Path(''),Root('results')

【讨论】:

@KyleRone 乐于助人【参考方案2】:

在 SQL Server 中,XML 变量、列或 FOR XML 查询结果表示“XML 片段”,没有单个***元素。

如果您想要一个 XML 文档(带有***根元素)的 FOR XML 查询,请为 FOR XML 添加 ROOT 参数。

【讨论】:

你能解释一下我如何改变我的 SQL 来使用它吗?我尝试用“for xml auto, root”替换最后一行最后的“for xml auto, elements”,所做的只是在我的问题中在格式错误的 xml 周围添加一个根元素。我需要将根元素称为结果,就像我的问题一样。 除了缺少单个根元素之外,XML 格式有什么问题? 这就是我的意思,没有一个根元素。但不幸的是,答案并不像添加根元素那么简单,因为我需要将结果节点作为根元素,更新了我的问题以解释原因。 我不确定您需要什么。您能否编辑问题以包括示例表 DDL、源数据和所需的 XML 输出?【参考方案3】:

如果我正确理解您的问题,您应该将每个表的查询合并在一起,然后应用 XML 格式。像这样……

WITH resultdata AS
(
    SELECT (
               SELECT *
               FROM   (
                          SELECT *
                          FROM   Table1 (NOLOCK)
                          WHERE  column1 = 99999
                                 AND column2 = -1
                          UNION ALL
                          SELECT *
                          FROM   Table2 (NOLOCK)
                          WHERE  column1 = 99999
                                 AND column2 = -1
                          UNION ALL
                          SELECT *
                          FROM   Table3 (NOLOCK)
                          WHERE  column1 = 99999
                                 AND column2 = -1
                          UNION ALL
                          SELECT *
                          FROM   Table4 (NOLOCK)
                          WHERE  column1 = 99999
                                 AND column2 = -1
                          UNION ALL
                          SELECT *
                          FROM   Table5 (NOLOCK)
                          WHERE  column1 = 99999
                                 AND column2 = -1
                          UNION ALL
                          SELECT *
                          FROM   Table6 (NOLOCK)
                          WHERE  column1 = 99999
                                 AND column2 = -1
                          UNION ALL
                          SELECT *
                          FROM   Table7 (NOLOCK)
                          WHERE  column1 = 99999
                                 AND column2 = -1
                          UNION ALL
                          SELECT *
                          FROM   Table8 (NOLOCK)
                          WHERE  column1 = 99999
                                 AND column2 = -1
                      ) AS x
               FOR XML AUTO, TYPE
           ) AS tabledata
)
SELECT * FROM resultdata AS result FOR XML AUTO, ELEMENTS;

【讨论】:

所以当我编辑我的实际查询看起来像这样时,我最终得到了这个错误:“使用 UNION、INTERSECT 或 EXCEPT 运算符组合的所有查询必须在其目标列表中有相同数量的表达式。”在实际查询中,一些子查询使用 *,而另一些则明确说明他们想要哪些列。这可能是问题吗?如果是这种情况,那么我不确定这是否可行,每个表都是半唯一的,但它们肯定不会都有相同数量的列。 如果它们的列数不同,则不能使用 UNION。 嗯,好吧。我想我必须回到绘图板上。谢谢你的知识。【参考方案4】:

下面的解决方案如何允许从具有不同结构的 DB 表中构造具有根的最终 XML。

SQL

-- DDL and sample data population, start
DECLARE @tbl1 TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, city VARCHAR(30));
INSERT INTO @tbl1
VALUES
('Miami')
, ('Orlando');

DECLARE @tbl2 TABLE (ID INT IDENTITY(1,1) PRIMARY KEY, [state] VARCHAR(30));
INSERT INTO @tbl2
VALUES
('Florida')
, ('Texas');
-- DDL and sample data population, end

WITH resultdata (tabledata) AS
(
    SELECT 
    (
        SELECT * FROM @tbl1
        FOR XML PATH('row'), TYPE, ROOT('tbl1')
    ) AS [tbl1]
    UNION ALL
    SELECT
    (   
        SELECT * FROM @tbl2
        FOR XML PATH('row'), TYPE, ROOT('tbl2')
    )
)
SELECT * 
FROM resultdata
FOR XML PATH(''), TYPE, ROOT('result');

输出 XML

<result>
  <tabledata>
    <tbl1>
      <row>
        <ID>1</ID>
        <city>Miami</city>
      </row>
      <row>
        <ID>2</ID>
        <city>Orlando</city>
      </row>
    </tbl1>
  </tabledata>
  <tabledata>
    <tbl2>
      <row>
        <ID>1</ID>
        <state>Florida</state>
      </row>
      <row>
        <ID>2</ID>
        <state>Texas</state>
      </row>
    </tbl2>
  </tabledata>
</result>

【讨论】:

以上是关于以 XML 形式检索 SQL 数据的问题的主要内容,如果未能解决你的问题,请参考以下文章

以 IEnumerable 形式检索 Json 数据

Java 8:以数据表的形式存储和检索数据

如何以数组形式检索 JTable 数据

如何把XML里面的节点内容以DataSet的形式返回出来,求代码

Django 以 5 个成员组的形式检索数据

Firebase 以 firebase:authUser 的形式检索存储在本地存储中的用户数据: