2013-08-19 61 views
2

我想轉換存儲過程返回定義的數據類型回表中的特定用戶的結果。Sql Server FOR XML AUTO並返回用戶定義的表類型?

這是基於這裏提出的想法: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不回來爲@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的解決方案:

  • 正確對待 「[」 作爲正在生成的SQL錯誤「語法錯誤附近 '[' ,預計會有「節點測試」。
  • 修正的聲明爲(MAX)的任何生成,因爲這將產生NVARCHAR(-1)

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' 

回答

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) 
+1

感謝Devart,@Roman ......得到了我所需要的。 – TheEdge

+0

不客氣@TheEdge :) – Devart

3

有是這裏的幾個問題:

  • 你的表是表變量,因此要獲得你要查詢sys.table_types架構。
  • 當您選擇for xml for auto,您的節點元素名稱將XML安全@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' 

sql fiddle demo

+0

С我發現我們的答案之間的根本區別? – Devart

+1

我的答案是顯示OP代碼中的所有錯誤,問題不僅僅是表變量,還有存儲過程中的xpath。 xpath like'/ [dbo]。[MyType]'由於無效的xml字符而不起作用。我同意最好在類型名稱前添加模式,儘管 –

+0

+1,並感謝您的答案。 – Devart

相關問題