sql - 多列的动态/条件枚举

标签 sql sql-server sql-server-2016

我正在尝试找出将多列枚举为两行的最佳方法。例如,下面的数据包含公司中每个职位的员工总数,并按全职等效 (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-0660P8 为 1,P9 为 6。因此,应该有 1 行 PositionSlotDescriptionP8 和 6 行 PositionSlotDescriptionP9PositionSlots 应为 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                      |
+---------------+--------------+-------------------------+

引用:


对于较大的集合,您可以将 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/

相关文章:

azure - SQL Server 2016 中始终加密的行为

sql - sql pre 和deploy 是否在一个 session 中运行

java - 数据输出流错误

sql-server - 如何仅在 tsql 中从计数中扩展行

SQL 仅选择缺失和更新的行

sql-server - SQL 用聚集列存储索引替换所有表

SQL Server - PK 删除性能不佳

sql - 在 postgres 中生成星期间隔日期

sql - PostgreSQL:一次运行多个选择

sql - 获取第二个和第四个斜杠之间的子字符串