如何按TypeId将记录分配至重复列并填充对应值?
动态列转行:按TypeId拆分并填充对应列
需求说明
需要将源表按TypeId拆分,为每个TypeId生成对应的ColA.N、ColB.N、ColC.N列,并将同位置的记录按行对齐填充。
源表结构及数据
| Id | TypeId | ColA | ColB | ColC |
|---|---|---|---|---|
| 0 | 0 | valA0 | valB0 | valC0 |
| 1 | 0 | valA1 | valB1 | valC1 |
| 2 | 0 | valA2 | valB2 | valC2 |
| 3 | 1 | valA3 | valB3 | valC3 |
| 4 | 1 | valA4 | valB4 | valC4 |
| 5 | 1 | valA5 | valB5 | valC5 |
| 6 | 2 | valA6 | valB6 | valC6 |
| 7 | 2 | valA7 | valB7 | valC7 |
| 8 | 2 | valA8 | valB8 | valC8 |
期望输出
| ColA.0 | ColB.0 | ColC.0 | ColA.1 | ColB.1 | ColC.1 | ColA.2 | ColB.2 | ColC.2 |
|---|---|---|---|---|---|---|---|---|
| valA0 | valB0 | valC0 | valA3 | valB3 | valC3 | valA6 | valB6 | valC6 |
| valA1 | valB1 | valC1 | valA4 | valB4 | valC4 | valA7 | valB7 | valC7 |
| valA2 | valB2 | valC2 | valA5 | valB5 | valC5 | valA8 | valB8 | valC8 |
疑问
之前找到过仅适用于硬编码固定数量TypeId的方案,但我的TypeId是动态的(数量1到n),想知道有没有不用游标就能实现的方法?如果必须用游标,我更倾向于在应用逻辑里处理。
解决方案
1. SQL端:动态SQL实现(无需游标)
这种场景属于动态列透视,可以通过拼接SQL语句实现,核心是先获取所有唯一的TypeId,再生成对应的列和聚合逻辑。以SQL Server为例:
-- 生成带行号的临时结果,用于后续行对齐 WITH RankedData AS ( SELECT TypeId, ColA, ColB, ColC, ROW_NUMBER() OVER (PARTITION BY TypeId ORDER BY Id) AS RowNum FROM YourSourceTable ) -- 动态拼接透视所需的列名 DECLARE @PivotColumns NVARCHAR(MAX), @Sql NVARCHAR(MAX) SELECT @PivotColumns = STRING_AGG( QUOTENAME(ColName + '.' + CAST(TypeId AS VARCHAR)), ', ' ) FROM ( SELECT DISTINCT TypeId, ColName FROM RankedData CROSS JOIN (VALUES ('ColA'), ('ColB'), ('ColC')) AS Cols(ColName) ) AS Combined -- 拼接并执行完整的透视SQL SET @Sql = N' SELECT ' + @PivotColumns + N' FROM ( SELECT RowNum, ColName + ''.'' + CAST(TypeId AS VARCHAR) AS PivotCol, ColValue FROM RankedData UNPIVOT ( ColValue FOR ColName IN (ColA, ColB, ColC) ) AS Unpvt ) AS SourceData PIVOT ( MAX(ColValue) FOR PivotCol IN (' + @PivotColumns + N') ) AS PivotResult ORDER BY RowNum' EXEC sp_executesql @Sql
2. 应用端处理(更灵活,适配动态TypeId)
如果不想在SQL端写动态逻辑,应用层处理会更直观,步骤如下:
- 查询所有数据,按
TypeId分组并为每组记录添加行号 - 收集所有
TypeId和最大行号 - 按行号遍历,将每个
TypeId对应行的字段值映射到目标列
以C#伪代码为例:
// 从数据库查询并分组数据 var groupedData = dbContext.YourSourceTable .OrderBy(x => x.Id) .GroupBy(x => x.TypeId) .Select(g => new { TypeId = g.Key, Rows = g.Select((row, index) => new { RowNum = index + 1, row.ColA, row.ColB, row.ColC }).ToList() }) .ToList(); // 获取所有TypeId和最大行号 var allTypeIds = groupedData.Select(g => g.TypeId).ToList(); var maxRowNum = groupedData.Max(g => g.Rows.Count); // 构建结果集 var result = new List<Dictionary<string, string>>(); for (int row = 1; row <= maxRowNum; row++) { var resultRow = new Dictionary<string, string>(); foreach (var typeGroup in groupedData) { var dataRow = typeGroup.Rows.FirstOrDefault(r => r.RowNum == row); resultRow.Add($"ColA.{typeGroup.TypeId}", dataRow?.ColA ?? string.Empty); resultRow.Add($"ColB.{typeGroup.TypeId}", dataRow?.ColB ?? string.Empty); resultRow.Add($"ColC.{typeGroup.TypeId}", dataRow?.ColC ?? string.Empty); } result.Add(resultRow); }
内容的提问来源于stack exchange,提问作者Nicolas
相关产品推荐
相关产品推荐

