SQL 枢轴 table 的一半
SQL Pivot Half of table
我有一个包含时间信息的 table。基本上是:
员工、日期、顺序、上班时间、下班时间。
他们一天可以多次下班,所以我试图在一行中一天内完成所有下班。我的结果是这样的:
员工、日期、TimeIn1、TimeOut1、TimeIn2、TimeOut2、TimeIn3、TimeOut3....
其中1、2、3为序号。我知道我可以根据 employee=employee、date=date 和 seq=seq+1 对 table 本身做一堆左连接,但是有没有办法在 pivot 中做到这一点?我不想旋转员工和日期字段,只想旋转时间和时间。
简短的回答是:是的,这是可能的。
确切的代码将被更新if/when你提供了示例数据来澄清一些要点,但是你绝对可以pivot
超时而单独留下employee/work日期。
对不起代码墙; fiddle 个站点中的 none 个在我当前的计算机上工作
declare @test table (
pk int,
workdate date,
seq int,
tIN time,
tOUT time
)
insert into @test values
(1, '2020-11-25', 1, '08:00', null),
(1, '2020-11-25', 2, null, '11:00'),
(1, '2020-11-25', 3, '11:32', null),
(1, '2020-11-25', 4, null, '17:00'),
(2, '2020-11-25', 5, '08:00', null),
(2, '2020-11-25', 6, null, '09:00'),
(2, '2020-11-25', 7, '09:15', null),
-- new date
(1, '2020-11-27', 8, '08:00', null),
(1, '2020-11-27', 9, null, '08:22'),
(1, '2020-11-27', 10, '09:14', null),
(1, '2020-11-27', 11, null, '12:08'),
(1, '2020-11-27', 12, '01:08', null),
(1, '2020-11-27', 13, null, '14:40'),
(1, '2020-11-27', 14, '14:55', null),
(1, '2020-11-27', 15, null, '17:00')
select *
from (
/* this just sets the column header names and condenses their values */
select
pk,
workdate,
colName = case when tin is not null then 'TimeIn' + cast(empDaySEQ as varchar) else 'TimeOut' + cast(empDaySEQ as varchar) end,
colValue = coalesce(tin, tout)
from (
/* main query */
select
pk,
workdate,
/* grab what pair # this clock in or out is; reset by employee & date */
empDaySEQ = (row_number() over (partition by pk, workdate order by seq) / 2) + (row_number() over (partition by pk, workdate order by seq) % 2),
tin,
tout
from @test
) i
) a
PIVOT (
max(colValue)
for colName
IN ( /* replace w/ dynamic if you don't know upper boundary of max in/out pairs */
[TimeIn1],
[TimeOut1],
[TimeIn2],
[TimeOut2],
[TimeIn3],
[TimeOut3],
[TimeIn4],
[TimeOut4]
)
) mypivotTable
(我会提供一个 fiddle 演示,但它们今天对我不起作用)
我有一个包含时间信息的 table。基本上是:
员工、日期、顺序、上班时间、下班时间。
他们一天可以多次下班,所以我试图在一行中一天内完成所有下班。我的结果是这样的:
员工、日期、TimeIn1、TimeOut1、TimeIn2、TimeOut2、TimeIn3、TimeOut3....
其中1、2、3为序号。我知道我可以根据 employee=employee、date=date 和 seq=seq+1 对 table 本身做一堆左连接,但是有没有办法在 pivot 中做到这一点?我不想旋转员工和日期字段,只想旋转时间和时间。
简短的回答是:是的,这是可能的。
确切的代码将被更新if/when你提供了示例数据来澄清一些要点,但是你绝对可以pivot
超时而单独留下employee/work日期。
对不起代码墙; fiddle 个站点中的 none 个在我当前的计算机上工作
declare @test table (
pk int,
workdate date,
seq int,
tIN time,
tOUT time
)
insert into @test values
(1, '2020-11-25', 1, '08:00', null),
(1, '2020-11-25', 2, null, '11:00'),
(1, '2020-11-25', 3, '11:32', null),
(1, '2020-11-25', 4, null, '17:00'),
(2, '2020-11-25', 5, '08:00', null),
(2, '2020-11-25', 6, null, '09:00'),
(2, '2020-11-25', 7, '09:15', null),
-- new date
(1, '2020-11-27', 8, '08:00', null),
(1, '2020-11-27', 9, null, '08:22'),
(1, '2020-11-27', 10, '09:14', null),
(1, '2020-11-27', 11, null, '12:08'),
(1, '2020-11-27', 12, '01:08', null),
(1, '2020-11-27', 13, null, '14:40'),
(1, '2020-11-27', 14, '14:55', null),
(1, '2020-11-27', 15, null, '17:00')
select *
from (
/* this just sets the column header names and condenses their values */
select
pk,
workdate,
colName = case when tin is not null then 'TimeIn' + cast(empDaySEQ as varchar) else 'TimeOut' + cast(empDaySEQ as varchar) end,
colValue = coalesce(tin, tout)
from (
/* main query */
select
pk,
workdate,
/* grab what pair # this clock in or out is; reset by employee & date */
empDaySEQ = (row_number() over (partition by pk, workdate order by seq) / 2) + (row_number() over (partition by pk, workdate order by seq) % 2),
tin,
tout
from @test
) i
) a
PIVOT (
max(colValue)
for colName
IN ( /* replace w/ dynamic if you don't know upper boundary of max in/out pairs */
[TimeIn1],
[TimeOut1],
[TimeIn2],
[TimeOut2],
[TimeIn3],
[TimeOut3],
[TimeIn4],
[TimeOut4]
)
) mypivotTable
(我会提供一个 fiddle 演示,但它们今天对我不起作用)