我想将存储过程的结果转换回一个特定的用户定义数据类型。
这是基于此处提出的想法:http://sqlblogcasts.com/blogs/danny/archive/2008/01/06/for-xml-and-back-again.aspx
例如,如果我有一个声明为:
的类型CREATE TYPE [dbo].[MyType]
AS TABLE
(
Id INT IDENTITY,
MonthNumber INT,
YearNumber INT,
NumberOfOfficersMakingReferrals INT,
TierLevel NVARCHAR(10),
TierStrengthTotal INT
)
GO
这样称呼:
DECLARE @Data [dbo].[MyType]
INSERT INTO @Data
EXEC [dbo].[sp_MyProc]
SET @Xml = (SELECT * FROM @Data FOR XML AUTO)
SELECT @Xml
-- Get a table back
EXEC uSpShredUserDefinedTableType @Xml, '[dbo].[MyType]'
GO
但是我编写的SP返回NULL,因为XML的NODE名称不会返回@UserTableType:
CREATE PROC dbo.uSpShredUserDefinedTableType @Xml XML, @UserTableType SYSNAME AS
DECLARE @Sql NVARCHAR(MAX)
SELECT @Sql = 'SELECT ' +
STUFF((SELECT ' ,T.Data.value(''@' +
c.name + ''', ''' +
t.name +
CASE WHEN c.user_type_id IN (165,167,173,175,231,239)
THEN '(' + CONVERT(VARCHAR, c.max_length) + ')'
WHEN c.user_type_id IN (106, 108)
THEN '(' + CONVERT(VARCHAR, c.precision)
+ ', ' + CONVERT(VARCHAR, c.scale) + ')'
ELSE '' END +
''') AS ' + c.name + CHAR(10)
FROM sys.columns c
INNER JOIN sys.types t ON c.user_type_id = t.user_type_id
WHERE object_id IN (SELECT type_table_object_id
FROM sys.table_types
WHERE name = @UserTableType)
AND t.name !='xml'
FOR XML PATH('')), 1, 7, '') +
'FROM @Xml.nodes(''/' + @UserTableType + ''') T(Data)'
EXEC sp_executesql @Sql, N'@Xml XML', @Xml = @Xml
GO
所以任何人都可以在上面的存储过程中看到我出错的地方,这样我可以使其功能与Danny的示例相同,但是对于用户定义的表类型?
[编辑:最终解决方案]
我不得不将Devart的解决方案修改为:
PROC:
CREATE PROC [generator].[sp_ShredUserDefinedTableType]
@AXml XML,
@AUserTableType SYSNAME
AS
DECLARE @Sql NVARCHAR(MAX)
SELECT @Sql = 'SELECT ' +
STUFF((SELECT ' ,T.Data.value(''@' +
c.name + ''', ''' +
t.name +
CASE WHEN c.user_type_id IN (165,167,173,175,231,239)
THEN '(' + CASE (c.max_length)
WHEN -1 THEN 'MAX'
ELSE
CONVERT(VARCHAR, c.max_length)
END + ')'
WHEN c.user_type_id IN (106, 108)
THEN '(' + CONVERT(VARCHAR, c.precision) + ', ' + CONVERT(VARCHAR, c.scale) + ')'
ELSE
''
END + ''') AS ' + c.name + CHAR(10)
FROM sys.table_types tt
JOIN sys.columns c ON tt.type_table_object_id = c.[object_id]
JOIN sys.types t ON c.user_type_id = t.user_type_id
WHERE SCHEMA_NAME(tt.[schema_id]) + '.' + tt.name = @AUserTableType
AND t.name != 'xml'
FOR XML PATH('')), 1, 7, '') +
'FROM @Xml.nodes(''/' + @AUserTableType + ''') T(Data)'
-- Print out the SQL that is necessary to query the XML that has been generated
PRINT @sql
GO
可以按如下方式调用:
DECLARE @Xml XML
DECLARE @Data [dbo].[t_sp_Report_AR102_DataRetrieval_V1_1_Result]
INSERT INTO @Data
EXEC [dbo].[sp_Report_AR102_DataRetrieval_V1_1]
@AOfficerParticipationNumberOfPriorDays = 30
,@AStartDate = '2013-04-01'
,@AEndDate = '2013-06-30'
,@AReferringServiceID = 4
,@AExcludePresentingIssueIDs = ''
,@AResultAsXML = @Xml OUTPUT
SET @Xml = (SELECT * FROM @Data FOR XML raw('dbo.t_sp_Report_AR102_DataRetrieval_V1_1_Result'))
EXEC [generator].[sp_ShredUserDefinedTableType] @Xml, 'dbo.t_sp_Report_AR102_DataRetrieval_V1_1_Result'
答案 0 :(得分:3)
这里有几个问题:
sys.table_types
。for xml for auto
时,您的节点元素名称将是xml safe @Data - <_x0040_Data ...
,因此我建议用户xml path
。您的代码变为:
CREATE PROC dbo.uSpShredUserDefinedTableType @Xml XML, @UserTableType SYSNAME AS
DECLARE @Sql NVARCHAR(MAX)
SELECT @Sql = 'SELECT ' +
STUFF((SELECT ' ,T.Data.value(''@' +
c.name + ''', ''' +
t.name +
CASE WHEN c.user_type_id IN (165,167,173,175,231,239)
THEN '(' + CONVERT(VARCHAR, c.max_length) + ')'
WHEN c.user_type_id IN (106, 108)
THEN '(' + CONVERT(VARCHAR, c.precision)
+ ', ' + CONVERT(VARCHAR, c.scale) + ')'
ELSE '' END +
''') AS ' + c.name + CHAR(10)
FROM sys.table_types tt
JOIN sys.columns c ON tt.type_table_object_id = c.[object_id]
JOIN sys.types t ON c.user_type_id = t.user_type_id
WHERE tt.name = @UserTableType
AND t.name != 'xml'
FOR XML PATH('')), 1, 7, '') +
'FROM @Xml.nodes(''/' + @UserTableType + ''') T(Data)'
--select @sql
EXEC sp_executesql @Sql, N'@Xml XML', @Xml = @Xml
GO
你称之为
SET @Xml = (SELECT * FROM @Data FOR XML raw('MyType'))
EXEC uSpShredUserDefinedTableType @Xml, 'MyType'
答案 1 :(得分:2)
试试这个 -
DECLARE @Xml XML, @UserTableType SYSNAME = '[dbo].[MyType]'
DECLARE @Sql NVARCHAR(MAX)
SELECT @Sql = 'SELECT ' +
STUFF((SELECT ' ,T.Data.value(''@' +
c.name + ''', ''' +
t.name +
CASE WHEN c.user_type_id IN (165,167,173,175,231,239)
THEN '(' + CONVERT(VARCHAR, c.max_length) + ')'
WHEN c.user_type_id IN (106, 108)
THEN '(' + CONVERT(VARCHAR, c.precision)
+ ', ' + CONVERT(VARCHAR, c.scale) + ')'
ELSE '' END +
''') AS ' + c.name + CHAR(10)
FROM sys.table_types tt
JOIN sys.columns c ON tt.type_table_object_id = c.[object_id]
JOIN sys.types t ON c.user_type_id = t.user_type_id
-- your mistake: [dbo].[MyType] != MyType
WHERE '[' + SCHEMA_NAME(tt.[schema_id]) + '].[' + tt.name + ']' = @UserTableType
AND t.name != 'xml'
FOR XML PATH('')), 1, 7, '') +
'FROM @Xml.nodes(''/' + @UserTableType + ''') T(Data)'
PRINT @Sql
输出 -
SELECT T.Data.value('@Id', 'int') AS Id
,T.Data.value('@MonthNumber', 'int') AS MonthNumber
,T.Data.value('@YearNumber', 'int') AS YearNumber
,T.Data.value('@NumberOfOfficersMakingReferrals', 'int') AS NumberOfOfficersMakingReferrals
,T.Data.value('@TierLevel', 'nvarchar(20)') AS TierLevel
,T.Data.value('@TierStrengthTotal', 'int') AS TierStrengthTotal
FROM @Xml.nodes('/[dbo].[MyType]') T(Data)