You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server无聚合实现行转列:日期分组转置多行数据

实现无聚合的行转列需求

原始数据表

Column AColumn B
01-01-202023
01-01-202024
01-01-202025
02-01-202011
02-01-202015

目标数据表

Column AColumn BColumn CColumn D
01-01-2020232425
02-01-20201115

普通PIVOT会默认使用聚合函数(如MAX/MIN),但你需要保留所有原始值而非聚合结果,核心解法是先给每个日期下的Column B值分配唯一组内序号,再基于序号做动态Pivot(因为最多有200个值,无法写死列名)。

以SQL Server为例的具体实现

  1. 给每行添加组内序号
    用窗口函数ROW_NUMBER()按日期分组,给每个Column B值标记唯一序号,确保同一日期下的每个值都有独立标识:
SELECT 
    ColumnA,
    ColumnB,
    -- 生成目标列名:Column B、Column C...对应序号1、2...
    'Column ' + CHAR(66 + ROW_NUMBER() OVER (PARTITION BY ColumnA ORDER BY ColumnB) - 1) AS NewColName,
    ROW_NUMBER() OVER (PARTITION BY ColumnA ORDER BY ColumnB) AS Seq
FROM YourTableName
  1. 动态生成Pivot查询
    因为列数最多200,需要动态拼接SQL语句,避免硬编码:
DECLARE @cols NVARCHAR(MAX), @query NVARCHAR(MAX)

-- 生成所有需要的列名(最多200列)
SELECT @cols = STRING_AGG(QUOTENAME(NewColName), ', ')
FROM (
    SELECT DISTINCT 
        'Column ' + CHAR(66 + ROW_NUMBER() OVER (PARTITION BY ColumnA ORDER BY ColumnB) - 1) AS NewColName
    FROM YourTableName
) t
WHERE CHARINDEX('Column ', NewColName) = 1 -- 确保列名格式正确

-- 拼接完整的动态Pivot语句
SET @query = N'
SELECT ColumnA, ' + @cols + N'
FROM (
    SELECT 
        ColumnA,
        ColumnB,
        ''Column '' + CHAR(66 + ROW_NUMBER() OVER (PARTITION BY ColumnA ORDER BY ColumnB) - 1) AS NewColName
    FROM YourTableName
) src
PIVOT (
    MAX(ColumnB) -- 这里用MAX是因为每个(ColumnA, NewColName)组合仅对应一个值,聚合不改变结果
    FOR NewColName IN (' + @cols + N')
) piv
'

-- 执行动态SQL
EXEC sp_executesql @query

这里用MAX聚合是因为每个分组序号对应的数值唯一,所以聚合后还是原始值,完全不会影响结果,完美解决普通Pivot的聚合问题。

其他数据库的适配思路

  • MySQL:没有内置PIVOT,可以用GROUP_CONCAT拼接动态列,结合用户变量生成组内序号,再通过动态SQL实现行转列。
  • PostgreSQL:使用crosstab函数,同样需要先给每行分配组内序号,再生成动态列完成转置。

核心逻辑一致:先给每个日期下的数值分配唯一组内标识,再基于标识做行转列,就能保留所有原始数据,避免聚合效果。

内容的提问来源于stack exchange,提问作者user3998893

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 23:50:34