我正在尝试找出将多列枚举为两行的最佳方法。例如,下面的数据包含公司中每个职位的员工总数,并按全职等效 (FTE) 状态进行分割。
+---------------+--------------+-------------------------+------+------+------+------+------+------+------+
| Position | PositionSlot | PositionSlotDescrpition | PD | P5 | P6 | P7 | P8 | P9 | FT |
+---------------+--------------+-------------------------+------+------+------+------+------+------+------+
| 1-400400-0680 | NULL | NULL | 7 | 1 | 2 | NULL | 1 | 18 | NULL |
| 1-400400-0041 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | 1 |
| 1-400400-0660 | NULL | NULL | NULL | NULL | NULL | NULL | 1 | 6 | NULL |
+---------------+--------------+-------------------------+------+------+------+------+------+------+------+
因此,对于职位 1-400400-0680
,有 29 名员工,如上所列。
我需要枚举这些聚合,以便为每个 Position
创建一个顺序 PositionSlot
(与 FTE 突破相关)。
- 每个
位置
的总行数应等于PD、P5、P6、P7、P8、P9和FT
列的总和。 PositionsSlotDescription
应为原始列名称PD、P5、P6、P7、P8、P9 和 FT
PositionSlot
应该对这些行进行连续编号。 槽的顺序并不重要。因此,PositionSlot = 1
可以属于任何PositionsSlotDescription
- 应重复
PositionsSlotDescription
/ 根据原始聚合中的数量进行复制。
例如,位置 1-400400-0660
的 P8
为 1,P9
为 6。因此,应该有 1 行 PositionSlotDescription
为 P8
和 6 行 PositionSlotDescription
为 P9
, PositionSlots
应为 1-7
预期结果
+---------------+--------------+-------------------------+
| Position | PositionSlot | PositionSlotDescrpition |
+---------------+--------------+-------------------------+
| 1-400400-0041 | 1 | FT |
| 1-400400-0660 | 1 | P8 |
| 1-400400-0660 | 2 | P9 |
| 1-400400-0660 | 3 | P9 |
| 1-400400-0660 | 4 | P9 |
| 1-400400-0660 | 5 | P9 |
| 1-400400-0660 | 6 | P9 |
| 1-400400-0660 | 7 | P9 |
| 1-400400-0680 | 1 | P5 |
| 1-400400-0680 | 2 | P6 |
| 1-400400-0680 | 3 | P6 |
| 1-400400-0680 | 4 | P8 |
| 1-400400-0680 | 5 | P9 |
| 1-400400-0680 | 6 | P9 |
| 1-400400-0680 | 7 | P9 |
| 1-400400-0680 | 8 | P9 |
| 1-400400-0680 | 9 | P9 |
| 1-400400-0680 | 10 | P9 |
| 1-400400-0680 | 11 | P9 |
| 1-400400-0680 | 12 | P9 |
| 1-400400-0680 | 13 | P9 |
| 1-400400-0680 | 14 | P9 |
| 1-400400-0680 | 15 | P9 |
| 1-400400-0680 | 16 | P9 |
| 1-400400-0680 | 17 | P9 |
| 1-400400-0680 | 18 | P9 |
| 1-400400-0680 | 19 | P9 |
| 1-400400-0680 | 20 | P9 |
| 1-400400-0680 | 21 | P9 |
| 1-400400-0680 | 22 | P9 |
| 1-400400-0680 | 23 | PD |
| 1-400400-0680 | 24 | PD |
| 1-400400-0680 | 25 | PD |
| 1-400400-0680 | 26 | PD |
| 1-400400-0680 | 27 | PD |
| 1-400400-0680 | 28 | PD |
| 1-400400-0680 | 29 | PD |
+---------------+--------------+-------------------------+
测试脚本
declare @table table ( Position varchar(64) --UniqueIdentifier
,PositionSlot int
,PositionSlotDescrpition varchar(64)
,PD varchar(16)
,P5 varchar(16)
,P6 varchar(16)
,P7 varchar(16)
,P8 varchar(16)
,P9 varchar(16)
,FT varchar(16))
insert into @table
values
('1-400400-0680',NULL,NULL,7,1,2,NULL,1,18,NULL),
('1-400400-0041',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1),
('1-400400-0660',NULL,NULL,NULL,NULL,NULL,NULL,1,6,NULL)
declare @expectedResults table( Position varchar(64)
,PositionSlot int
,PositionSlotDescrpition varchar(64))
insert into @expectedResults
values
('1-400400-0041',1,'FT'),
('1-400400-0660',1,'P8'),
('1-400400-0660',2,'P9'),
('1-400400-0660',3,'P9'),
('1-400400-0660',4,'P9'),
('1-400400-0660',5,'P9'),
('1-400400-0660',6,'P9'),
('1-400400-0660',7,'P9'),
('1-400400-0680',1,'P5'),
('1-400400-0680',2,'P6'),
('1-400400-0680',3,'P6'),
('1-400400-0680',4,'P8'),
('1-400400-0680',5,'P9'),
('1-400400-0680',6,'P9'),
('1-400400-0680',7,'P9'),
('1-400400-0680',8,'P9'),
('1-400400-0680',9,'P9'),
('1-400400-0680',10,'P9'),
('1-400400-0680',11,'P9'),
('1-400400-0680',12,'P9'),
('1-400400-0680',13,'P9'),
('1-400400-0680',14,'P9'),
('1-400400-0680',15,'P9'),
('1-400400-0680',16,'P9'),
('1-400400-0680',17,'P9'),
('1-400400-0680',18,'P9'),
('1-400400-0680',19,'P9'),
('1-400400-0680',20,'P9'),
('1-400400-0680',21,'P9'),
('1-400400-0680',22,'P9'),
('1-400400-0680',23,'PD'),
('1-400400-0680',24,'PD'),
('1-400400-0680',25,'PD'),
('1-400400-0680',26,'PD'),
('1-400400-0680',27,'PD'),
('1-400400-0680',28,'PD'),
('1-400400-0680',29,'PD')
最佳答案
使用临时数字表和cross apply(values ...)
来逆透视您的数据:
;with numbers as (
select top (32) --<-- 32 works for the example, increase for larger sets
i=row_number() over(order by (select 1))
from master..spt_values
order by i
)
select
t.Position
, PositionSlot=row_number() over (
partition by t.Position
order by v.PositionSlotDescription, n.i
)
, v.PositionSlotDescription
from @table t
cross apply (values
('PD',PD),('P5',P5) ,('P6',P6) ,('P7',P7) ,('P8',P8) ,('P9',P9) ,('FT',FT)
) v (PositionSlotDescription, Amount)
inner join numbers n
on n.i <= v.amount
where v.Amount is not null
order by t.Position, v.PositionSlotDescription
rextester 演示:http://rextester.com/AMKCR70455
返回:
+---------------+--------------+-------------------------+
| Position | PositionSlot | PositionSlotDescription |
+---------------+--------------+-------------------------+
| 1-400400-0041 | 1 | FT |
| 1-400400-0660 | 1 | P8 |
| 1-400400-0660 | 2 | P9 |
| 1-400400-0660 | 3 | P9 |
| 1-400400-0660 | 4 | P9 |
| 1-400400-0660 | 5 | P9 |
| 1-400400-0660 | 6 | P9 |
| 1-400400-0660 | 7 | P9 |
| 1-400400-0680 | 1 | P5 |
| 1-400400-0680 | 2 | P6 |
| 1-400400-0680 | 3 | P6 |
| 1-400400-0680 | 4 | P8 |
| 1-400400-0680 | 5 | P9 |
| 1-400400-0680 | 6 | P9 |
| 1-400400-0680 | 7 | P9 |
| 1-400400-0680 | 8 | P9 |
| 1-400400-0680 | 9 | P9 |
| 1-400400-0680 | 10 | P9 |
| 1-400400-0680 | 11 | P9 |
| 1-400400-0680 | 12 | P9 |
| 1-400400-0680 | 13 | P9 |
| 1-400400-0680 | 14 | P9 |
| 1-400400-0680 | 15 | P9 |
| 1-400400-0680 | 16 | P9 |
| 1-400400-0680 | 17 | P9 |
| 1-400400-0680 | 18 | P9 |
| 1-400400-0680 | 19 | P9 |
| 1-400400-0680 | 20 | P9 |
| 1-400400-0680 | 21 | P9 |
| 1-400400-0680 | 22 | P9 |
| 1-400400-0680 | 23 | PD |
| 1-400400-0680 | 24 | PD |
| 1-400400-0680 | 25 | PD |
| 1-400400-0680 | 26 | PD |
| 1-400400-0680 | 27 | PD |
| 1-400400-0680 | 28 | PD |
| 1-400400-0680 | 29 | PD |
+---------------+--------------+-------------------------+
引用:
- Generate a set or sequence without loops - 1 - Aaron Bertrand
- Generate a set or sequence without loops - 2 - Aaron Bertrand
- Generate a set or sequence without loops - 3 - Aaron Bertrand
- The "Numbers" or "Tally" Table: What it is and how it replaces a loop - Jeff Moden
对于较大的集合,您可以将
cross join from master..spt_values
添加到上面的 number
cte,或将 numbers
cte 替换为此备用堆叠热膨胀系数:
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, numbers as (
select top(50000)
i=row_number() over (order by (select 1))
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
)
rextester 演示:http://rextester.com/OZZHR43374
关于sql - 多列的动态/条件枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45925773/