2

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

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

如何将查询包含在 Scarlar 函数中以用作计算列?

<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>
4

2 回答 2

2

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

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
于 2013-01-28T22:45:49.417 回答
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 演示多个返回值

不过,我建议最好的方法是发送 XML 本身,而不是将 LineID 作为参数发送。由于您需要一个计算列,您可以只发送 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

编辑

使用您的实际 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;
于 2013-01-28T22:40:16.573 回答