从SQL查询嵌套XML - 问题

时间:2018-05-16 17:08:31

标签: sql xml

所以这是我要找的成品:

<GPAutoActions>
 <createDispute>
  <transaction>
    <defaultKey>
      <custNo>10000000-AD</custNo>
      <invNo>28893848</invNo>
    </defaultKey>
  </transaction>
  <reason>405</reason>
  <amount>185.17</amount>  
  <pnote>Notes</pnote>
  <owner>LARRYGIST</owner>
 </createDispute>
</GPAutoActions>

这是表格结构

custno          invno    reason amount  pnote   owner
117455521-AD    28894882    405 972.04  Note    LARRYGIST
128623268-AD    28887277    405 182.99  Note    LARRYGIST
131537715-AD    28893848    405 185.17  Note    LARRYGIST
189063783-AD    28927273    405 777.49  Note    LARRYGIST

这是我正在使用的SQL:

Select 1 as TAG
, null as parent
, null as 'createDispute!1!'
, null as 'transaction!2!Element'
, null as 'defaultKey!3!'
, null as 'defaultKey!3!custno!Element'
, null as 'defaultKey!3!InvNo!Element'
, null as 'reason!4!'
UNION ALL
Select 2 as Tag
, 1 as Parent
, Null
, NULL
, null
, null
, null
, null
Union ALL
Select 3 as Tag
, 2 as Parent
, Null
, NULL
, null
, custno
, InvNo
, null
FROM [GetPaid_Sandbox].[dbo].[DisputeData]
Union ALL
Select 4 as Tag
, 2 as Parent
, Null
, NULL
, null
, null
, null
, reason
FROM [GetPaid_Sandbox].[dbo].[DisputeData]
for XML EXPLICIT

以下是返回的内容:

<createDispute>
  <transaction>
    <defaultKey>
      <custno>117455521-AD</custno>
      <InvNo>28894882</InvNo>
    </defaultKey>
    <defaultKey>
      <custno>128623268-AD</custno>
      <InvNo>28887277</InvNo>
    </defaultKey>
    <defaultKey>
      <custno>131537715-AD</custno>
      <InvNo>28893848</InvNo>
    </defaultKey>
    <defaultKey>
      <custno>189063783-AD</custno>
      <InvNo>28927273</InvNo>
    </defaultKey>
    <reason>405</reason>
    <reason>405</reason>
    <reason>405</reason>
    <reason>405</reason>
  </transaction>
</createDispute>

我不明白为什么<transaction>标记在每个<defaultKey>标记后没有关闭?我还需要在原因代码之后添加剩余的标签,但我被困在这里。我应该使用Explicit还是PATH会在这种情况下更好地工作?我不想从SQL做到这一点,但我不确定如何轻松完成它。

3 个答案:

答案 0 :(得分:1)

从您的代码中我假设这是SQL Server。但这并不完全确定......希望,我的魔法水晶球运作良好。下次请分析实际的RDBMS(供应商和版本)。

使用FOR XML EXPLICIT是一个痛苦的问题......这是一个很好的方法,几个世纪以前,今天应该更喜欢FOR XML PATH

您的目标很容易实现:

DECLARE @mockup TABLE(custno VARCHAR(100),invno INT,reason INT,amount DECIMAL(10,4),pnote VARCHAR(100),[owner] VARCHAR(100));
INSERT INTO @mockup VALUES
 ('117455521-AD',28894882,405,972.04,'Note','LARRYGIST')
,('128623268-AD',28887277,405,182.99,'Note','LARRYGIST')
,('131537715-AD',28893848,405,185.17,'Note','LARRYGIST')
,('189063783-AD',28927273,405,777.49,'Note','LARRYGIST');

- 查询将创建成品

中显示的XML
SELECT custno AS [transaction/defaultKey/custNo]
      ,invno AS  [transaction/defaultKey/invNo]
      ,reason
      ,amount
      ,pnote
      ,[owner]
FROM @mockup 
WHERE invno=28893848
FOR XML PATH('createDispute'),ROOT('GPAutoActions');

结果

<GPAutoActions>
  <createDispute>
    <transaction>
      <defaultKey>
        <custNo>131537715-AD</custNo>
        <invNo>28893848</invNo>
      </defaultKey>
    </transaction>
    <reason>405</reason>
    <amount>185.1700</amount>
    <pnote>Note</pnote>
    <owner>LARRYGIST</owner>
  </createDispute>
</GPAutoActions>

提示:FOR XML EXPLICIT仍然是正确的选择,如果需要CDATA部分或非常有名称空间的技巧。

但我不明白你的评论:我希望数据库中的每一行数据都返回一个结果集

你可能正在寻找这个:

SELECT outerTable.invno
,(
    SELECT innerTable.custno AS [transaction/defaultKey/custNo]
          ,innerTable.invno AS  [transaction/defaultKey/invNo]
          ,innerTable.reason
          ,innerTable.amount
          ,innerTable.pnote
          ,innerTable.[owner]
    FROM @mockup AS innerTable
    WHERE innerTable.invno=outerTable.invno
    FOR XML PATH('createDispute'),ROOT('GPAutoActions'),TYPE
 )
 FROM @mockup AS outerTable;

答案 1 :(得分:0)

首先:看起来你在设置原因元素的父项时搞砸了。您的规范表明您希望reason成为createDispute元素的子元素。然而;您的查询将其设置为transaction的子元素。

要更正此问题,请将从parent返回reason的查询的2值更改为1。然后,您可以从同一查询中返回amountpnoteorder

下一步:您不需要第5列(defaultKey!3!) - 在所有查询中删除它。

然后:将null as 'createDispute!1!'更改为custno + '_' + cast(invno as varchar(50)) as 'createDispute!1!'。另外,将每个附加查询的第3个返回值编码为custno + '_' + cast(invno as varchar(50)),而不是返回null。

最后:ORDER BY custno + '_' + cast(invno as varchar(50))。这是将所有东西联系在一起的“特殊酱汁”。

应该这样做。快乐的编码!

TL:DR(重构):

Select 1 as TAG
, null as parent
, custno + '_' + cast(invno as varchar(50)) as 'createDispute!1!'
, null as 'transaction!2!reason!Element'
, null as 'transaction!2!amount!Element'
, null as 'transaction!2!pnote!Element'
, null as 'transaction!2!owner!Element'
, null as 'defaultKey!3!custno!Element'
, null as 'defaultKey!3!InvNo!Element'
FROM [GetPaid_Sandbox].[dbo].[DisputeData]
UNION ALL
Select 2 as Tag
, 1 as Parent
, custno + '_' + cast(invno as varchar(50))
, reason
, amount
, pnote
, [owner]
, null
, null
FROM [GetPaid_Sandbox].[dbo].[DisputeData]
Union ALL
Select 3 as Tag
, 2 as Parent
, custno + '_' + cast(invno as varchar(50))
, NULL
, NULL
, NULL
, NULL
, custno
, InvNo
FROM [GetPaid_Sandbox].[dbo].[DisputeData]
Union ALL
ORDER BY custno + '_' + cast(invno as varchar(50))
for XML EXPLICIT

答案 2 :(得分:0)

考虑嵌套查询:

SELECT 1 as TAG
, null as parent
, (SELECT 1 AS [Tag], NULL AS [Parent], sub.custno AS 'defaultKey!1!custno!Element', sub.invno AS 'defaultKey!1!invno!Element'
   FROM DisputeData sub
   WHERE d.custno = sub.custno
   FOR XML EXPLICIT, TYPE)  AS 'createDispute!1!transaction!Element'

, d.reason as 'createDispute!1!reason!Element'
, d.amount as 'createDispute!1!amount!Element'
, d.pnote as 'createDispute!1!pnote!Element'
, d.owner as 'createDispute!1!owner!Element'
FROM DisputeData As d
FOR XML EXPLICIT, ROOT('GPAutoActions');

Rextester Demo

不幸的是,这里的结果返回了嵌套元素 defaultKey 中众所周知的repeated namespaces问题,这里是一个空的:xmlns=""

<?xml version="1.0"?>
<GPAutoActions>
  <createDispute>
    <transaction>
      <defaultKey xmlns="">
        <custno>117455521-AD</custno>
        <invno>28894882</invno>
      </defaultKey>
    </transaction>
    <reason>405</reason>
    <amount>972.04</amount>
    <pnote>Dispute Reason: Inbound email from John requesting that account be cancelled, providing letter of cancellation. Attachments: Yes</pnote>
    <owner>LARRYGIST</owner>
  </createDispute>
  <createDispute>
    <transaction>
      <defaultKey xmlns="">
        <custno>128623268-AD</custno>
        <invno>28887277</invno>
      </defaultKey>
    </transaction>
    <reason>405</reason>
    <amount>182.99</amount>
    <pnote>Dispute Reason: Inbound email from Catherine requesting cancelation of services. Attachments: Yes</pnote>
    <owner>LARRYGIST</owner>
  </createDispute>
  <createDispute>
    <transaction>
      <defaultKey xmlns="">
        <custno>131537715-AD</custno>
        <invno>28893848</invno>
      </defaultKey>
    </transaction>
    <reason>405</reason>
    <amount>185.17</amount>
    <pnote>Dispute Reason: Syed stated that he canceled his Tyco contract a long time ago. Syad stated that he doesn't have an email address and didn't want to send CR a cancellation notice.  Attachments: No</pnote>
    <owner>LARRYGIST</owner>
  </createDispute>
  <createDispute>
    <transaction>
      <defaultKey xmlns="">
        <custno>189063783-AD</custno>
        <invno>28927273</invno>
      </defaultKey>
    </transaction>
    <reason>405</reason>
    <amount>777.49</amount>
    <pnote>Dispute Reason: Spoke to Grant stated moved out of building on 12 01 2017. Stated company that bought building decided not to go with Tyco and Tyco came and picked up the equipment. Attachments: No</pnote>
    <owner>LARRYGIST</owner>
  </createDispute>
</GPAutoActions>