TLDR: I have a scalar function, that expects a table-valued parameter and returns the XML representation of that table. Now I need to use this function in a larger Update statement, where the table-parameter of the function is generated by inner Select statements.
Hi,
We have an XML type definition, say [dbo].[XmlTestType], that looks like something this:
<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>
It basically represents a collection of Element-Content(s) mappings, which each Element (having a Name Attribute) containing N Elements (of type string).
We also have this Definition in Table-Type form:
CREATE TYPE [dbo].[TableTestType] AS TABLE ( [Element] VARCHAR(255) NOT NULL ,[Content] VARCHAR(255) NOT NULL ,PRIMARY KEY CLUSTERED ( [Element], [Content] ) );
So far so simple. We also have two functions, that can convert between the XML- and Table-representation of this data model:
- A scalar function with a table parameter of type [dbo].[TableTestType], that returns a xml of type [dbo].[XmlTestType]. Let’s call this one [dbo].[ConvertTableToXml].
- A table-valued function with a xml parameter of type [dbo].[XmlTestType], that returns a table of type [dbo].[TableTestType]. Let’s call this one [dbo].[ConvertXmlToTable].
We have a separate table, that uses the xml data type in one of its columns:
CREATE TABLE [dbo].[SomeTable] ( [UID] INT NOT NULL IDENTITY(1,1) ,[XmlData] XML (DOCUMENT [dbo].[XmlTestType]) NULL );
Everything is working fine so far, but now I need to update the XmlData inside the Table in an Update statement. For example, to modify the XmlData of all rows, to include the values of a separate table. So what I would like to do is something like this:
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]
Is anything like this possible? Meaning to call a scalar function, that expects a table-valued parameter, inside an Apply block, where the table-valued parameter is generated with inner select statements?
Right now I have no choice but to Cursor over the table, generate a table variable of type [dbo].[TableTestType] from the current state of the row, insert the missing entries into that variable, and convert the table back to XML; updating each row one by one.
Kind regards, Frank
Advertisement
Answer
[can I] call a scalar function, that expects a table-valued parameter, inside an Apply block
No. There is no way to construct a table-valued type in a SELECT. You must declare a variable of the table type and then INSERT it.
Alternatively you can embed the xml.nodes parsing logic that transforms the XML into a table into the body of the calling query.