SQL Server 2008 R2:通过函数从变量查询 xml 节点

SQL Server 2008 R2: Querying xml nodes from a variable through a function

我有两个单独的 xml 子结构相同的变量。 (即只有根和第一个节点名称不同,其余结构相同。) 我想创建一个函数,它接受 xml 变量和根节点的名称 & returns 我是一个包含所有项目的 table。

这些是我的 xml 定义(为简洁起见缩短)

declare @CartXml xml
Set @CartXml = ' <carts> 
<cart RefID="1" >

<Item SrNo="1" ProductCode="12" Qty="5">
</Item>

<Item SrNo="2" ProductCode="12" Qty="3">
</Item>
</cart>
</carts> '


declare @ProdXml xml
Set @ProdXml = ' <Products> 
<Product RefID="1" >

<Item SrNo="1" ProductCode="12" Qty="5">
</Item>

<Item SrNo="2" ProductCode="12" Qty="3">
</Item>
</Product>
</Products> '

我可以通过

等语句查询
 SELECT Hdr.x.value('@RefID', 'varchar(max)') CartID ,
       Det.*
 FROM   @CartXml.nodes('//carts/cart') AS Hdr(x)
 CROSS  APPLY 
          (
           SELECT 
            Det.c.value('@SrNo', 'varchar(max)') SrNo,
            Det.c.value('@ProductCode', 'varchar(max)') ProductCode,
            Det.c.value('@Qty', 'varchar(max)') Qty
            FROM   Hdr.x.nodes('Item') AS Det(c)
           ) Det

在上述查询中将 //carts/cart 替换为 //Products/Product 并将 @CartXml 替换为 @ProdXml 将给出相同的输出。

此查询封装在函数中时不起作用。

Create function fnTempGetprodInfoFromXml( @xml xml, @rootnode varchar(50))
returns table 
as
Return (
 SELECT Hdr.x.value('@RefID', 'varchar(max)') CartID ,
       Det.*
 FROM   @xml.nodes('//*[local-name()=sql:variable("@rootnode")]') AS Hdr(x)
 CROSS  APPLY 
          (
           SELECT 
            Det.c.value('@SrNo', 'varchar(max)') SrNo,
            Det.c.value('@ProductCode', 'varchar(max)') ProductCode,
            Det.c.value('@Qty', 'varchar(max)') Qty
            FROM   Hdr.x.nodes('Item') AS Det(c)
           ) Det
)
Go


--These Dont Work
Select * from fnTempGetprodInfoFromXml(@cartxml,'carts/cart')
Select * from fnTempGetprodInfoFromXml(@ProdXml,'Products/Product')

我觉得将节点变量传递给函数中的 xml.nodes 有一些问题。 我希望我可以传递 '//carts/cart' 而不是 'carts/cart' 但该函数无法编译。

这是函数需要的输出。

CartID  SrNo ProductCode    Qty
1       1     12            5
1       2     12            3

提前致谢。

您不能将参数传递给 nodes 函数,它必须是字符串文字。

您的选择是稍微修改您的函数以接受修剪后的 XML:

CREATE FUNCTION fnTempGetprodInfoFromXml (@xml XML)
RETURNS TABLE
AS
RETURN
(   SELECT  Det.c.value('@SrNo', 'varchar(max)') AS SrNo,
            Det.c.value('@ProductCode', 'varchar(max)') AS ProductCode,
            Det.c.value('@Qty', 'varchar(max)') AS Qty
    FROM    @xml.nodes('*/*/Item') AS Det(c)

);

然后叫法略有不同

DECLARE @Xml XML
SET @Xml = '<carts><cart RefID="1" ><Item SrNo="1" ProductCode="12" Qty="5">
            </Item><Item SrNo="2" ProductCode="12" Qty="3"></Item></cart></carts>';

 SELECT Hdr.x.value('@RefID', 'varchar(max)') CartID ,
        Det.*
 FROM   @Xml.nodes('//carts/cart') AS Hdr (x)
        CROSS APPLY fnTempGetprodInfoFromXml(x.query('*')) AS Det;

或者,如果您想要更通用,那么您可以使用通配符使您的函数仅 return 二级的所有项目,例如

DECLARE @Xml XML
SET @Xml = '<carts><cart RefID="1" ><Item SrNo="1" ProductCode="12" Qty="5">
            </Item><Item SrNo="2" ProductCode="12" Qty="3"></Item></cart></carts>';

SELECT  Hdr.x.value('@RefID', 'varchar(max)') CartID ,
        Det.*
FROM    @xml.nodes('*/*') AS Hdr(x)
        CROSS APPLY
        (   SELECT  Det.c.value('@SrNo', 'varchar(max)') AS SrNo,
                    Det.c.value('@ProductCode', 'varchar(max)') AS ProductCode,
                    Det.c.value('@Qty', 'varchar(max)') AS Qty
            FROM    hdr.x.nodes('Item') AS Det(c)
        ) Det;

除此之外,您将不得不使用动态 SQL,这意味着您不能使用函数。