SQL-Server 表中 XML 列中的复杂 XPath

问题描述 投票:0回答:1

我有一个表,其中包含 XML 列 XmlMsg。此 XmlMsg 可以包含“orderstatus”、“vehiclestatus”、....

我只对“orderstatus”感兴趣,更确切地说,对以下两种情况感兴趣:

  1. 最后一个订单部分是“待处理”。
  2. 最后一个订单部分是“待定”,最后一个订单部分是“完成”。

第一个示例如下(仅显示相关部分):

<orderstatus responsecode="0"
             ...
             numberoforderparts="3">
    ...
    <orderparts>
        <orderpart orderpartnumber="1"/>
        <orderpart orderpartnumber="2"/>
        <orderpart orderpartnumber="3">
            <eventtype>Pending</eventtype>
            ...
        </orderpart>
    </orderparts>
</orderstatus>

第二个示例如下(也仅显示相关部分):

<orderstatus responsecode="0"
             ...
             numberoforderparts="3">
    ...
    <orderparts>
        <orderpart orderpartnumber="1"/>
        <orderpart orderpartnumber="2">
            <eventtype>Complete</eventtype>
            ...
        </orderpart>
        <orderpart orderpartnumber="3">
            <eventtype>Pending</eventtype>
            ...
        </orderpart>
    </orderparts>
</orderstatus>

我能够得到第一个列表,如下:

SELECT *,
    XmlMsg.value('(/orderstatus/@numberoforderparts)[1]', 'INT') AS NumberOfOrderParts,
    
    -- Retrieve the last orderpart with eventtype="Pending"
    XmlMsg.query('(/orderstatus/orderparts/orderpart[@orderpartnumber = (/orderstatus/@numberoforderparts)[1] and eventtype="Pending"])[1]') AS LastOrderPart,
    
    -- Retrieve the second-to-last orderpart with eventtype="Complete"
    XmlMsg.query('(/orderstatus/orderparts/orderpart[@orderpartnumber = (/orderstatus/@numberoforderparts)[1] - 1 and eventtype="Complete"])[1]') AS PreviousOrderPart
FROM [dbo].[AWIMessageLogs]
WHERE Source='RCV_RESP' 
  AND LogDateTime >= '2024-11-26' 
  AND LogDateTime <= '2024-11-26 15:00' 
  AND XmlMsg.exist('/orderstatus') = 1
  -- Ensure that the last orderpart has eventtype="Pending"
  AND XmlMsg.query('(/orderstatus/orderparts/orderpart[@orderpartnumber = (/orderstatus/@numberoforderparts)[1] and eventtype="Pending"])[1]') IS NOT NULL

但是,我不知道如何获得第二个列表。

有人有想法吗?

sql sql-server xml xpath
1个回答
0
投票

使用节点方法通常更容易获得这些东西,例如:

CREATE TABLE #xml (x xml, id int IDENTITY)

INSERT INTO #xml VALUES(N'<orderstatus responsecode="0"
             numberoforderparts="3">
    
    <orderparts>
        <orderpart orderpartnumber="1"/>
        <orderpart orderpartnumber="2"/>
        <orderpart orderpartnumber="3">
            <eventtype>Pending</eventtype>
        </orderpart>
    </orderparts>
</orderstatus>'), ('<orderstatus responsecode="0"
             numberoforderparts="3">
    <orderparts>
        <orderpart orderpartnumber="1"/>
        <orderpart orderpartnumber="2">
            <eventtype>Complete</eventtype>
        </orderpart>
        <orderpart orderpartnumber="3">
            <eventtype>Pending</eventtype>
        </orderpart>
    </orderparts>
</orderstatus>')

SELECT  *
FROM    (
    SELECT  *
    ,   CASE 
            WHEN orderpart = max(orderpart) OVER(partition BY id) AND eventtype = 'Pending' -- Last pending
            OR (
                orderpart = max(orderpart) OVER(partition BY id) -1 AND eventtype = 'Complete' -- Complete and last is pending
                AND LEAD(eventtype) OVER(PARTITION BY ID ORDER BY orderpart) = 'Pending'
            )
        THEN 1 ELSE 0 END AS flag
    
    FROM    (
        SELECT  op.value('@orderpartnumber', 'int') AS orderpart, et.value('text()[1]', 'nvarchar(100)') AS eventtype
        ,   id
        FROM    #xml t
        CROSS apply x.nodes(N'orderstatus/orderparts/orderpart') t1(op)
        OUTER apply op.nodes(N'eventtype') t2(et)
        ) x
    ) x
WHERE   flag = 1

然后您可以使用一些 LAG/LEAD 来查找相关值,或者将数据放入临时表中并从那里进行处理。

输出:

订购部分 事件类型 id 旗帜
3 待定 1 1
2 完成 2 1
3 待定 2 1
© www.soinside.com 2019 - 2024. All rights reserved.