如何在SQL select语句中动态创建列

前端之家收集整理的这篇文章主要介绍了如何在SQL select语句中动态创建列前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有3张桌子.团队,选项,OptionTeam.
团队拥有TeamId和Name
Option包含OptionId,OptionGroup
OptionTeam持有TeamId,OptionId,OptionGroup
  1. select a.TeamId,a.Name
  2. (select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=4) as Option1,(select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=5) as Option2,(select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=6) as Option3,(select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=11) as Option4
  3. from Team a

我想获得一个团队列表,以及额外的列,表明每个团队有多少个选项连接到每个团队.这是通过上面的查询完成的,但我想用表Option中的OptionGroup替换4,5,6,11的值.
它必须是动态的,因为将来可能会有一个新的OptionGroup,我希望存储过程能够处理它.

样本数据:

  1. Team
  2. TeamId
  3. 1
  4. 2
  5. 3

选项

  1. OptionId | OptionGroup
  2. 11 | 4
  3. 12 | 5
  4. 13 | 4
  5. 14 | 4
  6. 15 | 5

OptionTeam

  1. TeamId | OptionId | OptionGroup
  2. 1 | 11 | 4
  3. 1 | 13 | 4
  4. 2 | 12 | 5
  5. 2 | 14 | 4
  6. 3 | 15 | 5

我想要的清单是

  1. TeamId | Group4 (OptionGroup=4) | Group5 (OptionGroup=5)
  2. 1 | 2 | 0
  3. 2 | 1 | 1
  4. 3 | 0 | 1

解决方法

你需要一个动态的支点才能做到这一点.这是存储过程:
  1. CREATE PROC [dbo].[pivotsp]
  2. @query AS NVARCHAR(MAX),-- The query,can also be the name of a table/view.
  3. @on_rows AS NVARCHAR(MAX),-- The columns that will be regular rows.
  4. @on_cols AS NVARCHAR(MAX),-- The columns that are to be pivoted.
  5. @agg_func AS NVARCHAR(257) = N'SUM',-- Aggregate function.
  6. @agg_col AS NVARCHAR(MAX),-- Column to aggregate.
  7. @output AS NVARCHAR(257) = N'',-- Table for results
  8. @debug AS bit = 0 -- 1 for debugging
  9. AS
  10.  
  11. -- Example usage:
  12. -- exec pivotsp
  13. -- 'select * from vsaleshistory',-- 'market,marketid,family,familyid,Forecaster,Forecasterid,product,productid',-- 'month',-- 'sum',-- 'ku',-- '##sales'
  14.  
  15. -- Input validation
  16. IF @query IS NULL OR @on_rows IS NULL OR @on_cols IS NULL
  17. OR @agg_func IS NULL OR @agg_col IS NULL
  18. BEGIN
  19. RAISERROR('Invalid input parameters.',16,1);
  20. RETURN;
  21. END
  22.  
  23. -- Additional input validation goes here (sql Injection attempts,etc.)
  24.  
  25. BEGIN TRY
  26. DECLARE
  27. @sql AS NVARCHAR(MAX),@cols AS NVARCHAR(MAX),@newline AS NVARCHAR(2);
  28.  
  29. SET @newline = NCHAR(13) + NCHAR(10);
  30.  
  31. -- If input is a valid table or view
  32. -- construct a SELECT statement against it
  33. IF COALESCE(OBJECT_ID(@query,N'U'),OBJECT_ID(@query,N'V')) IS NOT NULL
  34. SET @query = N'SELECT * FROM ' + @query;
  35.  
  36. -- Make the query a derived table
  37. SET @query = N'(' + @query + N') AS Query';
  38.  
  39. -- Handle * input in @agg_col
  40. IF @agg_col = N'*'
  41. SET @agg_col = N'1';
  42.  
  43. -- Construct column list
  44. SET @sql =
  45. N'SET @result = ' + @newline +
  46. N' STUFF(' + @newline +
  47. N' (SELECT N'','' + quotename( '
  48. + 'CAST(pivot_col AS sysname)' +
  49. + ') AS [text()]' + @newline +
  50. N' FROM (SELECT DISTINCT('
  51. + @on_cols + N') AS pivot_col' + @newline +
  52. N' FROM' + @query + N') AS DistinctCols' + @newline +
  53. N' ORDER BY pivot_col' + @newline +
  54. N' FOR XML PATH(''''))' + @newline +
  55. N',1,N'''');'
  56.  
  57. IF @debug = 1
  58. PRINT @sql
  59.  
  60. EXEC sp_executesql
  61. @stmt = @sql,@params = N'@result AS NVARCHAR(MAX) OUTPUT',@result = @cols OUTPUT;
  62.  
  63. IF @debug = 1
  64. PRINT @cols
  65.  
  66. -- Create the PIVOT query
  67. IF @output = N''
  68. begin
  69. SET @sql =
  70. N'SELECT *' + @newline +
  71. N'FROM (SELECT '
  72. + @on_rows
  73. + N',' + @on_cols + N' AS pivot_col'
  74. + N',' + @agg_col + N' AS agg_col' + @newline +
  75. N' FROM ' + @query + N')' +
  76. + N' AS PivotInput' + @newline +
  77. N' PIVOT(' + @agg_func + N'(agg_col)' + @newline +
  78. N' FOR pivot_col IN(' + @cols + N')) AS PivotOutput;'
  79. end
  80. ELSE
  81. begin
  82. set @sql = 'IF EXISTS (SELECT * FROM tempdb.sys.objects WHERE ' +
  83. 'name = ''' + @output + ''' AND type = N''U'') DROP TABLE tempdb.' + @output
  84. EXEC sp_executesql @sql;
  85.  
  86. SET @sql =
  87. N'SELECT * INTO ' + @output + @newline +
  88. N'FROM (SELECT '
  89. + @on_rows
  90. + N',' + @agg_col + N' AS agg_col' + @newline +
  91. N' FROM ' + @query + N')' +
  92. + N' AS PivotInput' + @newline +
  93. N' PIVOT(' + @agg_func + N'(agg_col)' + @newline +
  94. N' FOR pivot_col IN(' + @cols + N')) AS PivotOutput;'
  95. end
  96.  
  97. IF @debug = 1
  98. PRINT @sql
  99.  
  100. EXEC sp_executesql @sql;
  101. END TRY
  102. BEGIN CATCH
  103. DECLARE
  104. @error_message AS NVARCHAR(2047),@error_severity AS INT,@error_state AS INT;
  105.  
  106. SET @error_message = ERROR_MESSAGE();
  107. SET @error_severity = ERROR_SEVERITY();
  108. SET @error_state = ERROR_STATE();
  109.  
  110. RAISERROR(@error_message,@error_severity,@error_state);
  111.  
  112. RETURN;
  113. END CATCH

有了这个,很容易在可变数量的列上进行转换:

  1. EXEC pivotsp
  2. 'SELECT TeamID,OptionGroup,OptionID AS Options FROM OptionTeam','Teamid',-- Row headers
  3. 'optiongroup',-- item to aggregate
  4. 'count',-- aggregation function
  5. 'optiongroup',-- Column header
  6. '##temp' -- output table name
  7. SELECT * FROM ##temp

结果:

  1. Teamid 4 5
  2. 1 2 0
  3. 2 1 1
  4. 3 0 1

猜你在找的MsSQL相关文章