【问题标题】:Predefined column names in SQL Server pivot tableSQL Server 数据透视表中的预定义列名
【发布时间】:2011-01-16 04:46:01
【问题描述】:

前几天我在 StackOverflow (stackoverflow.com/questions/4663698/how-can-i-display-a-consolidated-version-of-my-sql-server-table) 中打开了一个主题。那时我需要有关如何在数据透视表上显示数据的帮助。根据我在论坛中获得的帮助,我的研究将我带到了这个关于动态 SQL 的页面:www.sommarskog.se/dynamic_sql.html。然后它把我引向了 Itzik Ben-Gan 的这个很棒的 SQL 脚本,它将创建一个存储过程,它完全按照我想要的方式输出数据透视表:sommarskog.se/pivot_sp.sp

嗯,差不多。我需要对此存储过程进行一次更改。我需要输出表以简单的 ASC 顺序保存通用列名,而不是从 SPROC 中的 @on_cols 变量中提取动态列名。例如,可能是 col1、col2、col3、col4 ...动态列名对我来说是个问题。所以我需要它们按它们出现的顺序按它们的索引命名。我已经尝试了各种方法来更改这个出色的 SQL 脚本,但它不起作用。

作者的代码我没有贴,因为太长了,但是链接above会带我们到那里。

任何帮助表示赞赏。非常感谢

【问题讨论】:

    标签: sql sql-server stored-procedures pivot-table


    【解决方案1】:

    你需要这个辅助函数,或者类似于将分隔列表(列名)拆分为行

    CREATE function dbo.values2table
    (
    @values varchar(max),
    @separator varchar(3),
    @limit int -- set to -1 for no limit
    ) returns @res table (id int identity, [value] varchar(max))
    as
    begin
    declare @value varchar(50)
    declare @commapos int, @lastpos int
    set @commapos = 0
    select @lastpos = @commapos, @commapos = charindex(@separator, @values, @lastpos+1)
    while @commapos > @lastpos and @limit <> 0
    begin
        select @value = substring(@values, @lastpos+1, @commapos-@lastpos-1)
        if @value <> '' begin
            insert into @res select ltrim(rtrim(@value))
            set @limit = @limit-1
        end
        select @lastpos = @commapos, @commapos = charindex(@separator, @values, @lastpos+1)
    end
    select @value = substring(@values, @lastpos+1, len(@values))
    if @value <> '' insert into @res select ltrim(rtrim(@value))
    return
    end
    GO
    

    然后将pivot_sp proc更改为以下 (SQL Server 支持多行字符串,所以我去掉了所有的“+ @newline +”)

    CREATE PROC dbo.pivot_sp
      @query    AS NVARCHAR(MAX),  -- The query, can also be the name of a table/view.
      @on_rows  AS NVARCHAR(MAX),  -- The columns that will be regular rows.
      @on_cols  AS NVARCHAR(MAX),  -- The columns that are to be pivoted.
      @agg_func AS NVARCHAR(257) = N'MAX', -- Aggregate function.
      @agg_col  AS NVARCHAR(MAX),  -- Column to aggregate.
      @generic  AS bit = 0,
      @debug    AS bit = 1
    AS
    
    -- Input validation
    IF @query IS NULL OR @on_rows IS NULL OR @on_cols IS NULL
       OR @agg_func IS NULL OR @agg_col IS NULL
    BEGIN
      RAISERROR('Invalid input parameters.', 16, 1);
      RETURN;
    END
    
    -- Additional input validation goes here (SQL Injection attempts, etc.)
    
    BEGIN TRY
      DECLARE
        @sql     AS NVARCHAR(MAX),
        @cols    AS NVARCHAR(MAX),
        @newline AS NVARCHAR(2);
    
      SET @newline = NCHAR(13) + NCHAR(10);
    
      -- If input is a valid table or view
      -- construct a SELECT statement against it
      IF COALESCE(OBJECT_ID(@query, N'U'),
                  OBJECT_ID(@query, N'V')) IS NOT NULL
        SET @query = N'SELECT * FROM ' + @query;
    
      -- Make the query a derived table
      SET @query = N'(' + @query + N') AS Query';
    
      -- Handle * input in @agg_col
      IF @agg_col = N'*'
        SET @agg_col = N'1';
    
      -- Construct column list
      SET @sql = N'
        SET @result = 
          STUFF(
            (SELECT N'','' +  quotename(
               CAST(pivot_col AS sysname)
               )  AS [text()]
             FROM (SELECT DISTINCT '
               + @on_cols + N' AS pivot_col
                   FROM' + @query + N') AS DistinctCols
             ORDER BY pivot_col
             FOR XML PATH(''''))
            ,1, 1, N'''');'
    
      IF @debug = 1
         PRINT @sql
    
      EXEC sp_executesql
        @stmt   = @sql,
        @params = N'@result AS NVARCHAR(MAX) OUTPUT',
        @result = @cols OUTPUT;
    
      DECLARE @colsout nvarchar(max)
      if @generic = 1
        select @colsout = coalesce(@colsout,'') + value + '] as col'+right(id,10)
        from dbo.values2table(left(@cols, LEN(@cols)-1), '],[', -1) X
      else
        select @colsout = @cols
    
      -- Create the PIVOT query
      SET @sql = N'
        SELECT ' + @on_rows + ',' + @colsout + '
          FROM (SELECT '
                  + @on_rows
                  + N', ' + @on_cols + N' AS pivot_col'
                  + N', ' + @agg_col + N' AS agg_col
              FROM ' + @query + N')' +
                  + N' AS PivotInput
          PIVOT(' + @agg_func + N'(agg_col)
            FOR pivot_col IN(' + @cols + N')) AS PivotOutput;'
    
        IF @debug = 1
           PRINT @sql
    
        EXEC sp_executesql @sql;
    
    END TRY
    BEGIN CATCH
      DECLARE
        @error_message  AS NVARCHAR(2047),
        @error_severity AS INT,
        @error_state    AS INT;
    
      SET @error_message  = ERROR_MESSAGE();
      SET @error_severity = ERROR_SEVERITY();
      SET @error_state    = ERROR_STATE();
    
      RAISERROR(@error_message, @error_severity, @error_state);
    
      RETURN;
    END CATCH
    GO
    

    这是一个您应该能够从任何 SQL Server 数据库运行的示例。

    exec dbo.pivot_sp @query = '
    select o.name object_name, c.system_type_id, c.name
    from sys.columns c
    inner join sys.objects o on o.object_id=c.object_id
    where o.is_ms_shipped = 0',
    @on_rows  = 'object_name',
    @on_cols  = 'system_type_id',
    @agg_func = N'COUNT', -- Aggregate function.
    @agg_col  = 'name',
    @generic=1,
    @debug=1
    

    【讨论】:

    • 嗨,cyberwiki,我非常感谢你的帮助。更新了我的 SPROC 并像魅力一样工作。
    猜你喜欢
    • 2013-05-12
    • 2012-10-10
    • 1970-01-01
    • 1970-01-01
    • 2016-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多