在 Apply 块中使用需要表参数的标量函数

Posted

技术标签:

【中文标题】在 Apply 块中使用需要表参数的标量函数【英文标题】:Using a Scalar Function that expects a Table Parameter inside an Apply block 【发布时间】:2020-12-02 06:23:54 【问题描述】:

TLDR:我有一个标量函数,它需要一个表值参数并返回该表的 XML 表示。现在我需要在更大的 Update 语句中使用这个函数,其中函数的表参数由内部 Select 语句生成。

嗨,

我们有一个 XML 类型定义,比如 [dbo].[XmlTestType],它看起来像这样:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="Root">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="Element" minOccurs="0" maxOccurs="unbounded">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="Content" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
                        </xsd:sequence>
                        <xsd:attribute name="Name" type="xsd:string" use="required"/>
                    </xsd:complexType>
                </xsd:element>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

它基本上表示元素-内容映射的集合,每个元素(具有名称属性)包含 N 个元素(字符串类型)。

我们也有这个表格类型的定义:

CREATE TYPE [dbo].[TableTestType] AS TABLE
(
     [Element] VARCHAR(255) NOT NULL
    ,[Content] VARCHAR(255) NOT NULL
    ,PRIMARY KEY CLUSTERED ( [Element], [Content] )
);

到目前为止很简单。我们还有两个函数,可以在此数据模型的 XML 和表格表示之间进行转换:

带有 [dbo].[TableTestType] 类型表参数的标量函数,它返回 [dbo].[XmlTestType] 类型的 xml。我们称它为 [dbo].[ConvertTableToXml]。 具有 [dbo].[XmlTestType] 类型的 xml 参数的表值函数,它返回 [dbo].[TableTestType] 类型的表。我们称它为 [dbo].[ConvertXmlToTable]。

我们有一个单独的表,它在其中一列中使用 xml 数据类型:

CREATE TABLE [dbo].[SomeTable]
(
    [UID] INT NOT NULL IDENTITY(1,1)
   ,[XmlData] XML (DOCUMENT [dbo].[XmlTestType]) NULL
);

到目前为止一切正常,但现在我需要在 Update 语句中更新 Table 内的 XmlData。 例如,要修改所有行的 XmlData,以包含单独表的值。 所以我希望 做这样的事情:

DECLARE @newDataForSomeTable AS TABLE
(
     [FK_dbo__SomeTable__UID] INT NOT NULL
    ,[Element] VARCHAR(255) NOT NULL
    ,[Content] VARCHAR(255) NOT NULL
);
/* @newDataForSomeTable gets filled */

UPDATE [tbl] SET [tbl].[XmlData] = [calc].[XmlData]
FROM [dbo].[SomeTable] AS [tbl]
CROSS APPLY
(
    SELECT [dbo].[ConvertTableToXml](
        SELECT
             [currentState].[Element]
            ,[currentState].[Content]
        FROM [dbo].[ConvertXmlToTable]([tbl].[XmlData]) AS [currentState]
    
        UNION

        SELECT
             [newData].[Element]
            ,[newData].[Content]
        FROM @newDataForSomeTable AS [newData]
        WHERE [newData].[FK_dbo__SomeTable__UID] = [tbl].[UID]
    ) AS [XmlData]
) AS [calc] 

这样的事情可能吗?意思是在 Apply 块内调用一个需要表值参数的标量函数,其中表值参数是使用内部 select 语句生成的?

现在我别无选择,只能将光标移到表上,从行的当前状态生成类型为 [dbo].[TableTestType] 的表变量,将缺少的条目插入该变量,然后将表转换回来转为 XML;逐行更新。

亲切的问候,弗兰克

【问题讨论】:

除了与 XML 之间的转换之外,您的函数中是否有任何特殊逻辑?否则,我不明白你为什么不能简化更新到UPDATE [tbl] SET [tbl].[XmlData] = [calc].[XmlData] FROM [dbo].[SomeTable] AS [tbl] JOIN @newDataForSomeTable AS [calc] ON [tbl].[UID]=[calc].[UID] 【参考方案1】:

[我可以] 在 Apply 块中调用一个标量函数,该函数需要一个表值参数

没有。无法在 SELECT 中构造表值类型。您必须声明一个表类型的变量,然后插入它。

或者,您可以嵌入 xml.nodes 解析逻辑,将 XML 转换为表到调用查询的正文中。

【讨论】:

以上是关于在 Apply 块中使用需要表参数的标量函数的主要内容,如果未能解决你的问题,请参考以下文章

在 Join 条件中使用标量函数

如何创建参数化递归 CTE 以展平标量函数中的层次结构?

准备好的语句中的 IBM DB2 标量函数参数

js中的callapplybind

javascript

Javascript中call和apply的区别与详解