我有下面的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>
答案 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;