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,这意味着您不能使用函数。
我有两个单独的 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,这意味着您不能使用函数。