Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何透视Datetime类型实现基于日期的检查_Sql_Sql Server 2005_Pivot_Unpivot - Fatal编程技术网

Sql 如何透视Datetime类型实现基于日期的检查

Sql 如何透视Datetime类型实现基于日期的检查,sql,sql-server-2005,pivot,unpivot,Sql,Sql Server 2005,Pivot,Unpivot,我想透视“Person\u Log”表数据。。 其栏目如下: EmployeeID-> Foreign key Log-> DateTime type “日志”的格式为“2013年1月22日下午2:02:34” 我想根据日志列中的日期检查创建数据透视,然后显示每个日期时间的最小值和最大值。。。 这是一种考勤报告。。 必需的列如下所示 EmployeeID, 01-Jan IN, 01-Jan OUT, 02-Jan IN, 02-Jan OUT, 03-Jan IN, 03-Jan

我想透视“Person\u Log”表数据。。 其栏目如下:

EmployeeID-> Foreign key
Log-> DateTime type
“日志”的格式为“2013年1月22日下午2:02:34”

我想根据日志列中的日期检查创建数据透视,然后显示每个日期时间的最小值和最大值。。。 这是一种考勤报告。。 必需的列如下所示

EmployeeID, 01-Jan IN, 01-Jan OUT, 02-Jan IN, 02-Jan OUT, 03-Jan IN, 03-Jan OUT.....and so on..
EmployeeID以外的列应该只包含从“日志”列提取的时间。。 对于提取,我使用convert(char(10),Log,101)表示日期,使用convert(char(5),Log,108)表示时间提取

我一天所能达到的最好成绩是:

SELECT   dbo.DoorLog.EmployeeID, 
         CONVERT(char(10), 
         MIN(dbo.DoorLog.DateTime), 101) AS Date, 
         CONVERT(char(8), MIN(dbo.DoorLog.DateTime), 108) AS INTime, 
         CONVERT(char(8), MAX(dbo.DoorLog.DateTime), 108) AS OUTTime, 
         dbo.Person.Name, dbo.Person.Department, dbo.Person.Sex, 
         dbo.Person.WorkUnit, 
         dbo.Person.Position
FROM dbo.DoorLog 
INNER JOIN dbo.Person ON dbo.DoorLog.EmployeeID = dbo.Person.EmployeeID
GROUP BY CONVERT(char(10), dbo.DoorLog.DateTime, 101), 
         dbo.DoorLog.EmployeeID, dbo.Person.Name, dbo.Person.Department, 
         dbo.Person.Sex, dbo.Person.WorkUnit, dbo.Person.Position;
请回复,因为我将在两天的截止日期前完成。。 提前谢谢

如你所问…样本数据

Log                           EmployeeID 
2013/01/31 12:31              11
2013/01/25 10:31              10
2013/01/23 13:29              8
2013/01/20 11:49              4

此数据转换是一个复杂的过程。在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)

下一步是
UNPIVOT
,它将获取输入/输出时间的单独列,并将它们放入多行:

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
看。结果如下所示:

| 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来生成结果,因为您很可能希望在任何一个月内都能动态生成结果。此的动态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)

两个查询的结果都是:

| 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) |

此数据转换是一个复杂的过程。在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)

下一步是
UNPIVOT
,它将获取输入/输出时间的单独列,并将它们放入多行:

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
看。结果如下所示:

| 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来生成结果,因为您很可能希望在任何一个月内都能动态生成结果。此的动态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)

两个查询的结果都是:

| 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) |

你能发布你的表格结构、样本数据和期望的结果吗?你的结果必须有多少列?@BlueFoots:我已经用样本数据编辑了这个问题。@HamletHakobyan:除了员工id,结果每天需要两列..一列显示输入时间,另一列显示输出时间。。同样,每天都需要两列作为每月的基础…你能发布你的表格结构吗,样本数据,然后是期望的结果?你的结果必须有多少列?@BlueFoots:我已经用样本数据编辑了这个问题。@HamletHakobyan:除了员工id,结果每天需要两列..一列显示输入时间,另一列显示输出时间。。同样地,每天都需要两个栏目作为每月的基础…尊重:)真的是一个详细而清晰的解释。。让我试试这个,然后再恢复。。谢谢你的努力……:)谢谢sql查询运行得非常完美。。但是我在使用动态查询时遇到了一些问题。。。我不清楚如何使用动态sql生成结果…@bluefeet…我一直在尝试在代码中使用此过程。。但是遇到了一个新问题。。希望能在这里寻求帮助。。尊敬:)真是一个精心设计、解释得很清楚的。。让我试试这个,然后再恢复。。谢谢你的努力……:)谢谢sql查询运行得非常完美。。但是我在使用动态查询时遇到了一些问题。。。我不清楚如何使用动态sql生成结果…@bluefeet…我一直在尝试在代码中使用此过程。。但是遇到了一个新问题。。希望能在这里寻求帮助。。