动态SQL实现可变行转列:将Bin位置转为字段值而非列名
解决方案
要实现你需要的格式,核心是先按SalesOrder+Line分组,给每组内的Bin行分配序号,再通过动态条件聚合将每个序号对应的Bin和Qty转为固定名称的列(Bin01/QTY01...Bin03/QTY03)。以下是调整后的代码:
DECLARE @maxSeq INT = 3; -- 支持最多3组Bin/QTY,可按需修改 DECLARE @cols NVARCHAR(MAX); -- 生成动态列列表:Bin01, QTY01, Bin02, QTY02, ..., BinN, QTYN SET @cols = STRING_AGG( CONCAT('MAX(CASE WHEN seq = ', n, ' THEN Bin END) AS Bin', FORMAT(n, '00'), ',', 'MAX(CASE WHEN seq = ', n, ' THEN StockQtyToShip END) AS QTY', FORMAT(n, '00')), ',' ) WITHIN GROUP (ORDER BY n) FROM (VALUES (1),(2),(3)) AS nums(n); -- 构建动态SQL查询 DECLARE @sql NVARCHAR(MAX) = CONCAT(' SELECT SalesOrder, SalesOrderLine AS Line, ', @cols, ' FROM ( -- 给每个SalesOrder+Line分组内的行分配序号 SELECT SalesOrder, SalesOrderLine, Bin, StockQtyToShip, ROW_NUMBER() OVER(PARTITION BY SalesOrder, SalesOrderLine ORDER BY Bin) AS seq FROM SorDetailBin ) AS t GROUP BY SalesOrder, SalesOrderLine '); EXEC sp_executesql @sql;
代码说明:
- 序号分配:用
ROW_NUMBER() OVER(PARTITION BY SalesOrder, SalesOrderLine ORDER BY Bin)给同一订单行下的每个Bin分配唯一序号(1-3),确保每个Bin/QTY对对应固定的列位置。 - 动态列生成:通过
STRING_AGG拼接出所有需要的Bin和Qty列,格式为Bin01, QTY01, Bin02, QTY02...,替换硬编码列名的同时支持扩展数量。 - 条件聚合:用
MAX(CASE WHEN ...)将每个序号对应的Bin值和Qty值映射到对应的列,最终按订单行分组聚合得到目标格式。
适配现有代码的关键点:
- 原代码错误地按Bin分区生成序号,导致无法按订单行分组;调整为按SalesOrder+SalesOrderLine分区,才是正确的分组维度。
- 放弃直接用
PIVOT(因为PIVOT只能针对单个聚合字段,无法同时处理Bin和Qty两个字段),改用条件聚合实现多字段的行转列。
如果需要支持更多组,只需修改@maxSeq的值,并在VALUES (1),(2),(3)中添加对应的数字即可。
内容的提问来源于stack exchange,提问作者St00ge
相关产品推荐
相关产品推荐

