このデータ変換はPIVOT
. SQL Server 2005+ には、データをローテーションする機能があります。希望する結果を得るには、いくつかの方法があります。どちらのバージョンもUNPIVOT
、関数とPIVOT
関数の両方を実装します。
サンプルデータ:
CREATE TABLE Person ([EmployeeId] int, [Name] varchar(4));
INSERT INTO Person ([EmployeeId], [Name])
VALUES
(11, 'Jim'),
(10, 'John'),
(8, 'Mary'),
(4, 'Tim');
CREATE TABLE DoorLog([EmployeeId] int, [DoorDate] datetime);
INSERT INTO DoorLog ([EmployeeId], [DoorDate])
VALUES
(11, '2013-01-31 12:31:00'),
(11, '2013-01-31 16:50:00'),
(11, '2013-01-31 17:50:00'),
(10, '2013-01-25 10:31:00'),
(10, '2013-01-25 16:45:00'),
(8, '2013-01-23 13:29:00'),
(8, '2013-01-23 18:25:00'),
(4, '2013-01-20 11:49:00'),
(4, '2013-01-20 19:10:00'),
(11, '2013-01-15 11:15:00'),
(11, '2013-01-15 16:25:00'),
(10, '2013-01-10 09:21:00'),
(10, '2013-01-10 15:45:00'),
(8, '2013-01-08 01:29:00'),
(8, '2013-01-08 02:25:00'),
(4, '2013-01-06 10:17:00'),
(4, '2013-01-06 19:10:00');
クエリは、各日付の最小/最大値を持つ従業員のリストを取得することから始まります。
select p.employeeid,
p.name,
convert(char(10),d.doordate, 101) date,
min(d.doordate) [In],
max(d.doordate) [Out]
from person p
left join doorlog d
on p.employeeid = d.employeeid
group by p.employeeid, p.name,
convert(char(10),d.doordate, 101)
デモで SQL Fiddle を参照してください
次のステップは、UNPIVOT
IN/OUT 時間の個別の列を取得し、それらを複数の行に配置することです。
select employeeid, name,
convert(char(8), doortime, 108) DoorTime,
date + '_'+ col as col_names
from
(
select p.employeeid,
p.name,
convert(char(10),d.doordate, 101) date,
min(d.doordate) [In],
max(d.doordate) [Out]
from person p
left join doorlog d
on p.employeeid = d.employeeid
group by p.employeeid, p.name,
convert(char(10),d.doordate, 101)
) src
unpivot
(
doortime
for col in ([In], [Out])
) unpiv
SQL Fiddle with Demoを参照してください。結果は次のようになります。
| EMPLOYEEID | NAME | DOORTIME | COL_NAMES |
-------------------------------------------------
| 4 | Tim | 10:17:00 | 01/06/2013_In |
| 4 | Tim | 19:10:00 | 01/06/2013_Out |
| 4 | Tim | 11:49:00 | 01/20/2013_In |
| 4 | Tim | 19:10:00 | 01/20/2013_Out |
この結果が得られたら、ピボットを適用できます。日付の値が事前にわかっている場合は、次のような値をハードコーディングできます。
select *
from
(
select employeeid, name,
convert(char(8), doortime, 108) DoorTime,
date + '_'+ col as col_names
from
(
select p.employeeid,
p.name,
convert(char(10),d.doordate, 101) date,
min(d.doordate) [In],
max(d.doordate) [Out]
from person p
left join doorlog d
on p.employeeid = d.employeeid
group by p.employeeid, p.name,
convert(char(10),d.doordate, 101)
) src
unpivot
(
doortime
for col in ([In], [Out])
) unpiv
) p
pivot
(
max(doortime)
for col_names in ([01/06/2013_In], [01/06/2013_Out],
[01/08/2013_In], [01/08/2013_Out],
[01/10/2013_In], [01/10/2013_Out],
[01/15/2013_In], [01/15/2013_Out],
[01/20/2013_In], [01/20/2013_Out],
[01/23/2013_In], [01/23/2013_Out],
[01/31/2013_In], [01/31/2013_Out])
) piv
SQL Fiddle with Demoを参照してください。
しかし、あなたの状況では、おそらく動的 SQL を使用して結果を生成する必要があるでしょう。これの動的 SQL バージョンは次のとおりです。
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(date +'_'+Logname)
from
(
select doordate,
convert(char(10),doordate, 101) date,
LogName
from DoorLog
cross apply
(
select 'In' LogName
union all
select 'Out'
) l
) s
group by convert(char(10), doordate, 112), date, Logname
order by convert(char(10), doordate, 112)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query
= 'select employeeid, name, '+@cols+'
from
(
select employeeid, name,
convert(char(8), doortime, 108) DoorTime,
date + ''_''+ col col_names
from
(
select p.employeeid,
p.name,
convert(char(10),d.doordate, 101) date,
min(d.doordate) [In],
max(d.doordate) [Out]
from person p
left join doorlog d
on p.employeeid = d.employeeid
group by p.employeeid, p.name,
convert(char(10),d.doordate, 101)
)src
unpivot
(
doortime
for col in ([In], [Out])
) unpiv
) p
pivot
(
max(doortime)
for col_names in('+@cols+')
) piv'
execute(@query)
SQL Fiddle with Demoを参照してください。
両方のクエリの結果は次のとおりです。
| EMPLOYEEID | NAME | 01/06/2013_IN | 01/06/2013_OUT | 01/08/2013_IN | 01/08/2013_OUT | 01/10/2013_IN | 01/10/2013_OUT | 01/15/2013_IN | 01/15/2013_OUT | 01/20/2013_IN | 01/20/2013_OUT | 01/23/2013_IN | 01/23/2013_OUT | 01/25/2013_IN | 01/25/2013_OUT | 01/31/2013_IN | 01/31/2013_OUT |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 11 | Jim | (null) | (null) | (null) | (null) | (null) | (null) | 11:15:00 | 16:25:00 | (null) | (null) | (null) | (null) | (null) | (null) | 12:31:00 | 17:50:00 |
| 10 | John | (null) | (null) | (null) | (null) | 09:21:00 | 15:45:00 | (null) | (null) | (null) | (null) | (null) | (null) | 10:31:00 | 16:45:00 | (null) | (null) |
| 8 | Mary | (null) | (null) | 01:29:00 | 02:25:00 | (null) | (null) | (null) | (null) | (null) | (null) | 13:29:00 | 18:25:00 | (null) | (null) | (null) | (null) |
| 4 | Tim | 10:17:00 | 19:10:00 | (null) | (null) | (null) | (null) | (null) | (null) | 11:49:00 | 19:10:00 | (null) | (null) | (null) | (null) | (null) | (null) |