2015-03-03 94 views
1

我有兩個獨立的具有相同子結構的xml變量。 (即只有根&第一個節點名稱不同,休息結構相同。) 我想創建一個函數,它需要xml變量&根節點的名稱&返回一個包含所有項目的表。SQL Server 2008 R2:通過函數從變量查詢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 

更換//車/車用//產品/產品&查詢這是我的XML定義(簡稱爲簡潔起見)@上面查詢中帶有@ProdXml的CartXml將提供相同的輸出。

此封裝在函數內的查詢不起作用。

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時會出現一些問題。 我希望我可以通過'//購物車/購物車'而不是'購物車/購物車',但該功能無法編譯。

這是該功能所需的輸出。

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

在此先感謝。

回答

0

您不能將參數傳遞給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; 

或者,如果你想成爲更通用的,那麼你可以做你的函數只需使用通配符來返回第二級的所有項目,例如

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; 

除此之外,你將不得不使用dymanic SQL,這將意味着你不能使用一個函數。