麻烦在SQL Server 2014中将XML数据转换为关系格式

时间:2018-02-23 14:59:25

标签: sql-server xml xpath xquery sql-server-2014

我得到了一些我需要“粉碎”的XML数据(我认为这是正确的术语)。那就是我需要把它放到SQL表中。这是一个例子,一个有效的查询,但我被告知这是低效的。如果您知道更有效的方法,请告诉我。

以下是一些示例XML,2个不起作用的查询,以及一个:

    DECLARE @XmlReportParameters NVARCHAR (MAX) = N'<?xml version="1.0" encoding="utf-16"?>
<Customers>
    <Customer>
        <Name>Sri Patel</Name>
        <FavColors>
            <FavColor>Red</FavColor>
            <FavColor>Blue</FavColor>
            <FavColor>Green</FavColor>
        </FavColors>
    </Customer>
    <Customer>
        <Name>Jane Doe</Name>
        <FavColors>
            <FavColor>Violet</FavColor>
            <FavColor>Mauve</FavColor>
        </FavColors>
    </Customer>
</Customers>
'

DECLARE @doc XML;
DECLARE @XmlTable TABLE
(
    XmlColumn XML NULL
);

SET @doc = @XmlReportParameters;

INSERT INTO @XmlTable
    ( XmlColumn )
VALUES
    ( @doc )

-- Wrong Way
SELECT
    tbl.col.value('(Name)[1]', 'nvarchar(max)')      AS CustomerName
   ,tbl.col.value('(FavColors/FavColor)[1]', 'nvarchar(max)')       AS FavColor
FROM
    @XmlTable   xt
    CROSS APPLY XmlColumn.nodes('/Customers/Customer') tbl(col);

-- Still wrong (but I'm not sure why)
SELECT
    tbl.col.value('(../Name)[1]', 'nvarchar(max)')      AS CustomerName
   ,tbl.col.value('(FavColor)[1]', 'nvarchar(max)')       AS FavColor
FROM
    @XmlTable   xt
    CROSS APPLY XmlColumn.nodes('/Customers/Customer/FavColors') tbl(col);

-- Right Way
SELECT
    tbl.col.value('(../../Name)[1]', 'nvarchar(max)')      AS CustomerName
   ,tbl.col.value('(.)[1]', 'nvarchar(max)')       AS FavColor
FROM
    @XmlTable   xt
    CROSS APPLY XmlColumn.nodes('/Customers/Customer/FavColors/FavColor') tbl(col);

返回:

CustomerName FavColor
------------ ----------
Sri Patel    Red
Jane Doe     Violet

CustomerName FavColor
------------ ----------
Sri Patel    Red
Jane Doe     Violet

CustomerName FavColor
------------ ----------
Sri Patel    Red
Sri Patel    Blue
Sri Patel    Green
Jane Doe     Violet
Jane Doe     Mauve

2 个答案:

答案 0 :(得分:3)

这里的“ineffecency”是使用Parent Axis遍历备份文档以获取名称。执行此操作的首选方法是使用多个APPLY运算符。第一个将突出显示Customer节点,然后是第二个用于投影FavColors节点的节点。像这样:

SELECT
    CustomerNode.e.value('(Name)[1]', 'nvarchar(max)')      AS CustomerName
   ,FavColorNode.e.value('(.)[1]', 'nvarchar(max)')       AS FavColor
FROM
    @XmlTable   xt
    CROSS APPLY XmlColumn.nodes('/Customers/Customer') CustomerNode(e)
    CROSS APPLY CustomerNode.e.nodes('FavColors/FavColor') FavColorNode(e);

虽然它们之间的差异可能不适用于大多数情况。

答案 1 :(得分:1)

正如我之前在另一个问题上告诉过你的那样,解决方案是对.nodes()的分层调用

SELECT
    cust.value('(Name/text())[1]', 'nvarchar(max)')      AS CustomerName
   ,col.value('text()[1]', 'nvarchar(max)')       AS FavColor
FROM
    @XmlTable   xt
    CROSS APPLY XmlColumn.nodes('/Customers/Customer') A(cust)
    CROSS APPLY cust.nodes('FavColors/FavColor') AS B(col) ;

这将首先返回所有<Customer>和 - 下面的 - 相关的<FavColor>

Customer    FavColor
Sri Patel   Red
Sri Patel   Blue
Sri Patel   Green
Jane Doe    Violet
Jane Doe    Mauve