SQL Server 表中 XML 列中的复杂 XPath

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

我有一个表,其中包含一个 XML 列

XmlMsg
。此列可以包含
orderstatus
vehiclestatus
、....

我只对

orderstatus
节点感兴趣,更确切地说,对以下两种情况感兴趣:

  1. 最后一个
    orderpart
    是“待处理”。
  2. 最后一个
    orderpart
    是“待定”,最后一个是“已完成”。

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

<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>Completed</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="Completed"
    XmlMsg.query('(/orderstatus/orderparts/orderpart[@orderpartnumber = (/orderstatus/@numberoforderparts)[1] - 1 and eventtype="Completed"])[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
3个回答
1
投票

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

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

1
投票

最后一个订单部分是“待处理”。

orderstatus[orderparts/orderpart[last()]/eventtype='Pending']

最后一个订单部分是“待定”,最后一个订单部分是“完成”。

orderstatus[orderparts/orderpart[last()]/eventtype='Pending' and
            orderparts/orderpart[last()-1]/eventtype='Complete']

1
投票

您可以对这两个查询使用 XPath 1.0:

  1. 获取最后一个

    orderstatus
    orderpart
    "Pending"
    节点:

    //orderstatus[
        orderparts[
          orderpart[last()][eventtype/text() = "Pending"]
        ]
    ]
    
  2. 获取最后一个

    orderstatus
    orderpart
    且倒数第二个为
    "Pending"
    "Complete"
    节点:

    //orderstatus[
        orderparts[
            orderpart[last()][eventtype/text() = "Pending"]
        ][
            orderpart[last() - 1][eventtype/text() = "Complete"]
        ]
    ]
    

db<>小提琴

© www.soinside.com 2019 - 2024. All rights reserved.