sql - 直接从用户定义的函数中选择 xml 节点

标签 sql sql-server xml function

我从 xml 中进行选择,它将属性解析为如下列:

declare @xml xml
select @xml = xml_Function()

SELECT
    Tab.Col.value('@fieldOne','varchar(20)') AS fieldOne,
    Tab.Col.value('@fieldTwo','varchar(20)') AS fieldTwo
FROM  @xml.nodes('/row') Tab(Col)

是否可以直接从 xml_Function 进行选择,而不将结果复制到 @xml 变量中?

类似于:

SELECT * 
FROM xml_Function().nodes('/row')

最佳答案

据我所知,您不能直接将 XML 返回函数与 nodes() 一起使用,但您可以使用 CTE 或“子选择”来内联它:

CREATE FUNCTION dbo.ComeBackAsXML(@XmlText VARCHAR(MAX))
RETURNS XML
AS
BEGIN
    DECLARE @x XML=CAST(@XmlText AS XML);
    RETURN @x;
END
GO 

DECLARE @xText VARCHAR(MAX)=
'<root>
  <item id="3">
    <a attr="test1" />
    <a attr="test2" />
    <a attr="test3" />
  </item>
  <item id="5">
    <a attr="test1" />
    <a attr="test2" />
  </item>
</root>';
WITH GetXml AS (SELECT dbo.ComeBackAsXml(@xText) AS AsXml)
SELECT item.value('@id','int') AS ItemID
      ,a.value('@attr','varchar(max)') AS a_Attr
FROM GetXml
CROSS APPLY GetXml.AsXml.nodes('/root/item') AS One(item)
CROSS APPLY One.item.nodes('a') AS The(a);
GO

DROP FUNCTION dbo.ComeBackAsXML;
GO

这是作为子选择的 CTE:

SELECT item.value('@id','int') AS ItemID
      ,a.value('@attr','varchar(max)') AS a_Attr
FROM (SELECT dbo.ComeBackAsXml(@xText)) AS GetXml(AsXml)
CROSS APPLY GetXml.AsXml.nodes('/root/item') AS One(item)
CROSS APPLY One.item.nodes('a') AS The(a);

如果您想让函数可参数化,您必须注意,您写入 XPath 表达式的内容(几乎在所有情况下)都是文字,因此不可参数化...

我假设您不希望使用“通用”XML 函数来处理您可能需要的任何未知结构。我假设有一个给定的 XML 始终相同,而您只想将查询写得更短:

你有好几条路要走

  • 交付表格并使用WHERE
  • 传入参数并将其与 sql:parameter() 一起使用
  • 动态构建语句(需要存储过程)

在这里您可以找到每种方法的示例:

CREATE FUNCTION dbo.ParseXML(@xml XML)
RETURNS TABLE
AS
RETURN
SELECT item.value('@id','int') AS ItemID
      ,a.value('@attr','varchar(max)') AS a_Attr
FROM @xml.nodes('/root/item') AS One(item)
CROSS APPLY One.item.nodes('a') AS The(a);
GO

DECLARE @x XML=
'<root>
  <item id="3">
    <a attr="test1" />
    <a attr="test2" />
    <a attr="test3" />
  </item>
  <item id="5">
    <a attr="test1" />
    <a attr="test2" />
  </item>
</root>';

SELECT * FROM dbo.ParseXML(@x)
WHERE ItemID=3
GO

ALTER FUNCTION dbo.ParseXML(@xml XML,@ItemID INT)
RETURNS TABLE
AS
RETURN
SELECT item.value('@id','int') AS ItemID
      ,a.value('@attr','varchar(max)') AS a_Attr
FROM @xml.nodes('/root/item[@id=sql:variable("@ItemID")]') AS One(item)
CROSS APPLY One.item.nodes('a') AS The(a);
GO

DECLARE @x XML=
'<root>
  <item id="3">
    <a attr="test1" />
    <a attr="test2" />
    <a attr="test3" />
  </item>
  <item id="5">
    <a attr="test1" />
    <a attr="test2" />
  </item>
</root>';

SELECT * FROM dbo.ParseXML(@x,5);
GO

CREATE PROCEDURE dbo.ParseXMLDynamically(@xml XML,@ItemID INT)
AS
BEGIN
    DECLARE @SqlCmd NVARCHAR(MAX)=
'SELECT item.value(''@id'',''int'') AS ItemID
      ,a.value(''@attr'',''varchar(max)'') AS a_Attr
FROM @xml.nodes(''/root/item[@id=' +  CAST(@ItemID AS VARCHAR(100)) + ']'') AS One(item)
CROSS APPLY One.item.nodes(''a'') AS The(a)';

EXECUTE sp_executesql @SqlCmd,N'@xml XML',@xml;
END
GO

DECLARE @x XML=
'<root>
  <item id="3">
    <a attr="test1" />
    <a attr="test2" />
    <a attr="test3" />
  </item>
  <item id="5">
    <a attr="test1" />
    <a attr="test2" />
  </item>
</root>';

EXEC dbo.ParseXMLDynamically @x, 5;
GO

DROP PROCEDURE dbo.ParseXMLDynamically;
DROP FUNCTION dbo.ParseXML;

关于sql - 直接从用户定义的函数中选择 xml 节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35039518/

相关文章:

SQL Server - 如何向上或向下舍入小数?

mysql - 在 MYSQL 中拆分和匹配字符串

sql - 将多个数据库迁移到一个 Azure SQL 数据库?

sql-server - sql server 是否介意记录插入的方式?

Sql 选择每个汇总组的前 3 个

用于解码 JAXB 对象的 Java 泛型

sql - 用SQL计算机器状态时间

mysql - 我的 MySQL 查询不会返回任何结果?

xml - 设置 xsl :value-of into an href attribute and the text field of a link in an XSLT

java - 如何在 XSD 中指定重复元素