【问题标题】:SQL - XML - Create multiple nodes with same name in subquerySQL - XML - 在子查询中创建多个具有相同名称的节点
【发布时间】:2019-12-05 12:24:33
【问题描述】:

我在从 SQL 生成 XML 文件时遇到问题。 通常它工作正常,但现在的问题是,我想在子查询中显示具有相同名称 <cbc:Note> 的多个节点。 我知道我可以在其间使用null 列强制拆分,但随后会生成一个新的InvoiceLine

原来的查询有1000多行代码,所以我只是贴出数据,这是需要的。

查询以这种方式开始:

WITH XMLNAMESPACES (
                        'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2' as ext,
                        'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' as cbc,
                        'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' as cac,
                        'http://uri.etsi.org/01903/v1.3.2#' as xades,
                        'http://www.w3.org/2001/XMLSchema-instance' as xsi,
                        'http://www.w3.org/2000/09/xmldsig#' as ds
                    )   

SELECT
    @XMLData = xmldat.xmldataCol 
FROM
(
    SELECT
        (

        SELECT
            -- HIER XML Daten generieren
            ''                                                              as 'ext:UBLExtensions',
            ''                                                              as 'ext:UBLExtensions/ext:UBLExtension',
            ''                                                              as 'ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent',
            '2.1'                                                           as 'cbc:UBLVersionID',
            'TR1.2'                                                         as 'cbc:CustomizationID',
            -- evtl. Kommentar für geschart = 1
            case 
            when v2.geschart != 1 then 'IHRACAT'
            else '###PROFILE###' end                                        as 'cbc:ProfileID',
            '###TRANSACTION_NO###'                                          as 'cbc:ID',
            'false'                                                         as 'cbc:CopyIndicator',
            ....

在代码中的某个位置,它会生成多个发票行。 在发票行中,我需要有多个 <cbc:Note> 节点。 这是代码:

        ...
        case when v2.RECINFW = 1 then
            cast(v2.kurs as decimal(18,4))              
        else
            null
        end                                         as 'cac:PricingExchangeRate/cbc:CalculationRate',
        /* 
            Invoice Lines
            | | | | | | | | | | | | | | | | |
            v v v v v v v v v v v v v v v v v
        */
        (
            SELECT 
                vp2.pos_nr                                                      as 'cac:InvoiceLine/cbc:ID',
                'PalWeight:' + cast(cast(isnull(vp2.gew_pal,'') as decimal(18,4)) as nvarchar(50))  as 'cbc:Note',
                'PackUnit:' + cast(cast(isnull(a.VERP_EIN,'') as decimal(18,4)) as nvarchar(50))            as 'cbc:Note',
                case when vp2.DRUCKFLG=4 then cast(isnull(vp2.BEMERK,'') as nvarchar(max)) else null end    as 'cbc:Note',
                ''                                                                                          as 'cbc:SomeOtherField',
                ...
            FROM 
                vorgpos2 vp2 (nolock)
            inner join
                artikel a (nolock) on vp2.ARTKENN = a._KENN
            WHERE 
                vp2.vorgang2 = v2._kenn FOR XML path (''), root('REPLACEINVOICELINEREPLACE'), type
        ),

当我在 cbc:Notes 列之间放置一个 null 时,

'PalWeight:' + cast(cast(isnull(vp2.gew_pal,'') as decimal(18,4)) as nvarchar(50))  as 'cbc:Note',
null,
'PackUnit:' + cast(cast(isnull(a.VERP_EIN,'') as decimal(18,4)) as nvarchar(50))            as 'cbc:Note',
null,
case when vp2.DRUCKFLG=4 then cast(isnull(vp2.BEMERK,'') as nvarchar(max)) else null end    as 'cbc:Note',

它破坏了完整的发票行(停止一个并创建一个新的):

<cac:InvoiceLine>
    <cbc:ID>1</cbc:ID>
    <cbc:Note>PalWeight:1000.0000</cbc:Note>
</cac:InvoiceLine>
<cac:InvoiceLine>
    <cbc:Note>PackUnit:25.0000</cbc:Note>
</cac:InvoiceLine>
<cac:InvoiceLine>
    <cbc:InvoicedQuantity unitCode="KGM">100.0000</cbc:InvoicedQuantity>
    ...

想要的结果:

<cac:InvoiceLine>
    <cbc:ID>1</cbc:ID>
    <cbc:Note>PalWeight:1000.0000</cbc:Note>
    <cbc:Note>PackUnit:25.0000</cbc:Note>
    <cbc:InvoicedQuantity unitCode="KGM">100.0000</cbc:InvoicedQuantity>
    ...

如果您想知道子查询中缺少 REPLACEINVOICELINEREPLACE 根元素。这是之后更换的。 有没有人提示或解决这个问题? 非常感谢!

【问题讨论】:

  • 是发票行存储在一个/单行或发票行是多行:FROM vorgpos2 vp2 (nolock) inner join artikel a (nolock) on vp2.ARTKENN = a._KENN --
  • 一行是一个发票行。但可以有多个发票行

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


【解决方案1】:

SQL XML 很奇怪。您可能想尝试以下方法(注意null as 'x' 列):

WITH XMLNAMESPACES (
  'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' as cbc,
  'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' as cac
)
SELECT
  pos_nr                                                      as 'cbc:ID',
  'PalWeight:' + cast(cast(isnull(gew_pal,'') as decimal(18,4)) as nvarchar(50))  as 'cbc:Note',
  null as 'x',
  'PackUnit:' + cast(cast(isnull(VERP_EIN,'') as decimal(18,4)) as nvarchar(50))            as 'cbc:Note',
  null as 'x',
  case when DRUCKFLG=4 then cast(isnull(BEMERK,'') as nvarchar(max)) else null end    as 'cbc:Note'
FROM (values
  (1, 1000.0, 25.0, 4, 100.0)
) dat (pos_nr, gew_pal, verp_ein, druckflg, bemerk)
FOR XML path ('cac:InvoiceLine'), root('foo'), type

产量:

<foo xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
  <cac:InvoiceLine>
    <cbc:ID>1</cbc:ID>
    <cbc:Note>PalWeight:1000.0000</cbc:Note>
    <cbc:Note>PackUnit:25.0000</cbc:Note>
    <cbc:Note>100.0</cbc:Note>
  </cac:InvoiceLine>
</foo>

信用到期:for xml path() concatenates texts, how to get 2 elements with the same name?

【讨论】:

  • 其实结果差不多。它关闭&lt;InvoiceLine&gt; 节点并在两行之后打开一个新的&lt;InvoiceLine&gt;
【解决方案2】:

您可以使用另一个子选择(如果您的数据是基于设置的,或者在两者之间使用更接近的 元素

        SELECT 
            vp2.pos_nr                                                      as 'cac:InvoiceLine/cbc:ID',
            'PalWeight:' + cast(cast(isnull(vp2.gew_pal,'') as decimal(18,4)) as nvarchar(50))  as 'cac:InvoiceLine/cbc:Note',
            NULL as'cac:InvoiceLine',
            'PackUnit:' + cast(cast(isnull(a.VERP_EIN,'') as decimal(18,4)) as nvarchar(50))            as 'cac:InvoiceLine/cbc:Note',
            NULL as'cac:InvoiceLine',
            case when vp2.DRUCKFLG=4 then cast(isnull(vp2.BEMERK,'') as nvarchar(max)) else null end    as 'cac:InvoiceLine/cbc:Note',
            ''                                                                                          as 'cac:InvoiceLine/cbc:SomeOtherField',
            ...
        FROM 

简而言之:

引擎打开&lt;cac:InvoiceLine&gt;,然后打开&lt;cbc:ID&gt;元素以将vb2.pos_nr插入为text()-node。
下一行告诉引擎路径'cac:InvoiceLine/cbc:Note'。引擎认为:“哦,&lt;cbc:ID&gt; 仅此而已,让我们关闭这个元素。啊,我们继续&lt;cac:InvoiceLine&gt;,它仍然打开。让我们插入一个&lt;cbc:Note&gt;
现在神奇的事情发生了:工程师认为:“好的,我们必须关闭 &lt;cbc:Node&gt;,但我们会在 &lt;cac:InvoiceLine&gt; 内继续。糟糕,没有可插入的内容......没关系,让我们选择下一个。好吧,我们仍在&lt;cac:InvoiceLine&gt; 内,但我们必须打开一个&lt;cbc:Node&gt; 元素。”
等等……

【讨论】:

    【解决方案3】:

    注意:注意将空字符串''转换为十进制,会报错

    select 'PalWeight:' + cast(cast(isnull(null,'') as decimal(18,4)) as nvarchar(50)) 
    go
    --concat is more flexible with null
    select concat('PalWeight:', null) 
    go
    

    xml部分:

    --edited this part, to include the attribute on a column (the attribute to a following element was apparently the culprit and i got confused as to how multi InvoiceLines could happen). 
    --Just adjust the other xml generation options accordingly.
    
    select
    pos_nr as 'InvoiceLine/ID',
    null as 'InvoiceLine',
    gew_pal as 'InvoiceLine/Note',
    null as 'InvoiceLine',
    verp_ein as 'InvoiceLine/Note',
    null as 'InvoiceLine',
    DRUCKFLG as 'InvoiceLine/Note',
    someothercol3 as 'InvoiceLine/someothercol1/@attributeofthefollowingcolumncol1', --<-- reason of confusion
    someothercol1 as 'InvoiceLine/someothercol1',
    someothercol2 as 'InvoiceLine/someothercol2' 
    from 
    (
    values(1, 'a1', 'b1', 'c1', 'd1', 'e1', 'f1'),(2, 'a2', 'b2', null, 'd2', null, 'f2'),(3, null, 'b3', 'c3', 'd3', null, null)
    ) as t(pos_nr, gew_pal, verp_ein, DRUCKFLG, someothercol1, someothercol2, someothercol3)
    for xml path('');
    
    
    select
    pos_nr as 'InvoiceLine/ID',
    (select 
        gew_pal as 'Note',
        null,
        verp_ein as 'Note',
        null,
        DRUCKFLG as 'Note',
        someothercol1 as 'someothercol1',
        someothercol2 as 'someothercol2' 
    for xml path(''), type
    ) as 'InvoiceLine/*'
    from 
    (
    values(1, 'a1', 'b1', 'c1', 'd1', 'e1', 'f1'),(2, 'a2', 'b2', null, 'd2', null, 'f2'),(3, null, 'b3', 'c3', 'd3', null, null)
    ) as t(pos_nr, gew_pal, verp_ein, DRUCKFLG, someothercol1, someothercol2, someothercol3)
    for xml path('');
    
    
    select
    pos_nr as 'ID',
    (select 
        gew_pal as 'Note',
        null,
        verp_ein as 'Note',
        null,
        DRUCKFLG as 'Note',
        someothercol1 as 'someothercol1',
        someothercol2 as 'someothercol2' 
    for xml path(''), type
    ) 
    from 
    (
    values(1, 'a1', 'b1', 'c1', 'd1', 'e1', 'f1'),(2, 'a2', 'b2', null, 'd2', null, 'f2'),(3, null, 'b3', 'c3', 'd3', null, null)
    ) as t(pos_nr, gew_pal, verp_ein, DRUCKFLG, someothercol1, someothercol2, someothercol3)
    for xml path('InvoiceLine');
    

    【讨论】:

    • 已编辑,添加了为 InvoiceLine 中的列创建属性
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多