在标量值函数中使用Xquery

时间:2013-01-28 21:58:32

标签: sql sql-server sql-server-2008 xquery

我有下面的Query返回我需要的信息,但是我需要在标量值函数中使用此查询来使用计算列中的返回值。

XML列位于同一个表中,我需要将Settings中的值插入名为Directions

的列中
;WITH XMLNAMESPACES ( 'http://www.w3.org/2001/XMLSchema' AS als )
SELECT
 a.a.value('@Settings', 'VARCHAR(50)') AS [Settings]

FROM Base AS X
    CROSS APPLY X.BaseXML.nodes('als:Name') a(a)

我正在尝试的功能,但没有到达任何地方

CREATE FUNCTION [dbo].[ChooseRevision](@lineId int) Returns integer As
Begin
Return (WITH XMLNAMESPACES ( 'http://www.w3.org/2001/XMLSchema' AS als )
SELECT
 a.a.value('@Settings', 'VARCHAR(50)') AS [Settings]

FROM Base AS X
    CROSS APPLY X.BaseXML.nodes('als:Name') a(a)
Where LineId = @lideid
)
End

GO

如何在一个疤痕函数中包含查询以用作计算列?

<als:Doc xmlns:als="http://www.w3.org/2001/XMLSchema" SchemaVersion="0.1" Settings="First Test" Title="Recovery Loop">
  <als:Base Rev="0" Id="201" />
  <als:Number TimeStamp="2013-01-21T15:08:00">
    <als:Member Name="Club Run" DirId="123" />
  </als:Number>
  </als:Doc>

2 个答案:

答案 0 :(得分:2)

假设每个XML值只有一个als:Name个节点,您可以这样写:

CREATE FUNCTION [dbo].[ChooseRevision](@lineId int) 
RETURNS VARCHAR(50) 
AS
BEGIN
  DECLARE @r VARCHAR(50);
  WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema' AS als)
  SELECT
   @r = BaseXML.value('als:Doc[1]/@Settings', 'VARCHAR(50)') 
  FROM Base
  WHERE LineId = @lineId;
  RETURN @r;
END

如果您打算在dbo.Base表中使用此功能,则应使用此版本:

CREATE FUNCTION [dbo].[ChooseRevision](@xml XML) 
RETURNS VARCHAR(50) 
AS
BEGIN
  DECLARE @r VARCHAR(50);
  WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema' AS als)
  SELECT @r = @xml.value('als:Doc[1]/@Settings', 'VARCHAR(50)') 
  RETURN @r;
END

答案 1 :(得分:1)

您尝试执行的操作的问题是,虽然您可能知道您的选择查询只返回一个结果,但数据库却没有。考虑这个示例模式

CREATE TABLE Base (BaseXML XML, Settings INT);
INSERT Base VALUES ('<root settings="1"><a>SomeXML</a></root>', NULL);

您知道设置只在根目录中出现一次,因此

SELECT  a.a.value('@settings', 'VARCHAR(50)') AS [Settings]
FROM    Base X
        CROSS APPLY X.BaseXML.nodes('root') a(a);

只会返回一个结果(对于每一行),但是,如果你采用这个模式:

CREATE TABLE Base2 (BaseXML XML, Settings INT);
INSERT Base2 VALUES ('<root><a settings="1">SomeXML</a><a settings="2">Some More XML</a></root>', NULL);

几乎相同的查询将返回2行:

SELECT  a.a.value('@settings', 'VARCHAR(50)') AS [Settings]
FROM    Base2 X
        CROSS APPLY X.BaseXML.nodes('root/a') a(a);

因此,您的函数不能用作标量函数。您需要通过使用[1]告诉SQL您只期望​​一个(第一个)值:

SELECT  BaseXML.value('/root[1]/@settings[1]', 'INT') AS Settings
FROM    Base;

<强> SQL FIddle to demonstrate multiple return values

我建议尽管这样做的最好方法是将LineID作为参数发送,而不是发送XML本身。由于您需要计算列,因此您只需发送XML数据并保存表的不必要的第二个查询:

CREATE FUNCTION dbo.ParseBaseSettings (@XML XML)
RETURNS INT
AS
BEGIN
    RETURN @XML.value('/root[1]/@settings[1]', 'INT');
END;

你可能需要在这里处理你的XML命名空间,但是为了我的缘故,我已经跳过了这个。

最后,您可以创建计算列:

CREATE TABLE Base 
(   BaseXML XML, 
    Settings AS dbo.ParseBaseSettings(BaseXML)
);

<强> SQL Fiddle of final solution

修改

使用您的实际XML数据,我编译了这个函数:

CREATE FUNCTION dbo.ParseBaseSettings (@XML XML)
RETURNS NVARCHAR(50)
AS
BEGIN
    DECLARE @Ret NVARCHAR(50);        
    WITH XMLNAMESPACES ('http://www.w3.org/2001/XMLSchema' AS als)
    SELECT  @Ret = @XML.value('/als:Doc[1]/@Settings', 'NVARCHAR(50)');

    RETURN @Ret;
END;