如何在表上使用pivot如datetime

时间:2014-11-08 15:31:00

标签: sql sql-server oracle sql-server-2008 pivot

我考虑过编写一个sql查询。 我有一张非常简单的桌子。该表中有两个字段。

CREATE TABLE [CHECKINOUT](
    [USERID] [int] NOT NULL,
    [CHECKTIME] [datetime] NOT NULL DEFAULT (getdate())
);GO

USERID  CHECKTIME
1   2014-11-04 08:24:49.000
1   2014-11-03 16:57:00.000
1   2014-11-03 08:15:54.000
1   2014-10-28 12:57:58.000
1   2014-10-28 08:22:46.000
1   2014-10-24 16:58:33.000
1   2014-10-24 12:53:06.000
1   2014-10-24 08:21:38.000
1   2014-10-22 16:19:55.000
1   2014-10-21 08:26:21.000

上面有样品表。 我想用pivot来编写这个简单的查询。 我写了一个数据透视查询,但返回的值为null。 我写了这样的查询。

SELECT [USERID],[MORN_IN],[MORN_OUT],[NOON_IN],[NOON_OUT] FROM  
( 
   SELECT [USERID], convert(NVARCHAR,  ([CHECKTIME]), 104) as DATE_TIME FROM [CHECKINOUT] 
) AS IN_OUT
PIVOT 
( 
 MAX(DATE_TIME) --TO DATE
 FOR DATE_TIME -- MY ROW COLUMN
 IN 
  ( 
  [MORN_IN],[MORN_OUT],[NOON_IN],[NOON_OUT]  --  MY ROW COLUMN
  ) 
) AS PIVOT_TABLE

查询结果不正确 -

USERID  MORN_IN MORN_OUT    NOON_IN NOON_OUT
1   NULL    NULL    NULL    NULL
2   NULL    NULL    NULL    NULL
3   NULL    NULL    NULL    NULL
4   NULL    NULL    NULL    NULL
5   NULL    NULL    NULL    NULL
6   NULL    NULL    NULL    NULL
7   NULL    NULL    NULL    NULL

我想做什么? 同一个用户在他们的动作当天 我想分成几块。

例如:

00:00-11:00 =>MORN_IN
11:00-13:00 =>MORN_OUT(first record ONLY MIN(11:00-13:00))
12:00-15:00 =>NOON_IN (second record max(12:00-13:00) NOON_IN > MORN_OUT)
15:00-00:00 =>NOON_OUT

SELECT TOP 3 [USERID]
      ,[CHECKTIME]
  FROM [CHECKINOUT] ORDER BY [USERID],[CHECKTIME] DESC

USERID my CHECKTIME
1 2014-10-24 16: 58: 33.000
1 2014-10-24 12: 53: 06,000
1 2014-10-24 08: 21: 38.000

现在转向数据透视表的结果(我不能做这部分。但是应该返回这样的结果)

USERID   MORN_IN                         MORN_OUT                 NOON_IN    NOON_OUT
1          2014-10-24 08: 21: 38.000  2014-10-24 12: 53: 06,000      NULL   2014-10-24 16: 58: 33.000

1

2 个答案:

答案 0 :(得分:1)

如果时间间隔13:00 - 16:30被认为是NOON_IN,那么以下查询:

SELECT DAY_DIVISION, [MORN_IN], [MORN_OUT], [NOON_IN], [NOON_OUT]
FROM
(SELECT CHECKTIME, CASE 
                     WHEN CAST(CHECKTIME as time) >= '00:00:00' AND CAST(CHECKTIME as time) < '11:00:00' THEN 'MORN_IN'
                     WHEN CAST(CHECKTIME as time) >= '11:00:00' AND CAST(CHECKTIME as time) < '13:00:00' THEN 'MORN_OUT'
                     WHEN CAST(CHECKTIME as time) >= '13:00:00' AND CAST(CHECKTIME as time) < '16:30:00' THEN 'NOON_IN'
                     WHEN CAST(CHECKTIME as time) >= '16:30:00' THEN 'NOON_OUT'
                  END AS TIME_DIVISION,
                  RANK() OVER ( ORDER BY CAST(CHECKTIME as date) ASC) AS DAY_DIVISION
FROM CHECKINOUT) AS SourceTable
PIVOT
(
MAX(CHECKTIME)
FOR TIME_DIVISION IN ([MORN_IN], [MORN_OUT], [NOON_IN], [NOON_OUT])
) AS PivotTable;

产生此输出:

DAY_DIVISION MORN_IN                    MORN_OUT                NOON_IN                 NOON_OUT
------------------------------------------------------------------------------------
1            2014-10-21 08:26:21.000    NULL                    NULL                    NULL
2            NULL                       NULL                    2014-10-22 16:19:55.000 NULL
3            2014-10-24 08:21:38.000    2014-10-24 12:54:06.000 NULL      2014-10-24 16:58:33.000
7            2014-10-28 08:22:46.000    2014-10-28 12:57:58.000 NULL    NULL
9            2014-11-03 08:15:54.000    NULL                    NULL    2014-11-03 16:57:00.000
11           2014-11-04 08:24:49.000    NULL                    NULL    NULL

答案 1 :(得分:0)

在12:00和13:00之间处理登录和多个用户ID。 (在Oracle 11.2上测试)

WITH
CheckInOutRaw(userID, checkTime) AS(
  SELECT 1, '2014-11-04 08:24:49.000' FROM DUAL UNION ALL
  SELECT 1, '2014-11-03 16:57:00.000' FROM DUAL UNION ALL
  SELECT 1, '2014-11-03 08:15:54.000' FROM DUAL UNION ALL
  SELECT 1, '2014-10-28 12:57:58.000' FROM DUAL UNION ALL
  SELECT 1, '2014-10-28 08:22:46.000' FROM DUAL UNION ALL
  SELECT 1, '2014-10-24 16:58:33.000' FROM DUAL UNION ALL
  SELECT 1, '2014-10-24 12:53:06.000' FROM DUAL UNION ALL
  SELECT 1, '2014-10-24 08:21:38.000' FROM DUAL UNION ALL
  SELECT 1, '2014-10-22 16:19:55.000' FROM DUAL UNION ALL
  SELECT 1, '2014-10-21 08:26:21.000' FROM DUAL UNION ALL
  SELECT 2, '2014-11-04 08:24:49.000' FROM DUAL UNION ALL
  SELECT 2, '2014-11-03 16:57:00.000' FROM DUAL UNION ALL
  SELECT 2, '2014-11-03 08:15:54.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-29 11:07:58.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-29 12:07:58.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-29 16:57:58.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-28 11:07:58.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-28 12:07:58.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-28 16:57:58.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-28 08:22:46.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-27 12:57:58.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-27 12:07:58.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-27 16:57:58.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-27 08:22:46.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-24 16:58:33.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-24 12:53:06.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-24 08:21:38.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-22 13:19:55.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-22 16:19:55.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-21 08:26:21.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-20 12:19:55.000' FROM DUAL UNION ALL
  SELECT 2, '2014-10-20 16:19:55.000' FROM DUAL
),
CheckInOutTemp AS (
  SELECT
    userID
    , TO_TIMESTAMP(checkTime, 'YYYY-MM-DD HH24:MI:SSXFF3') checkTime
  FROM
    CheckInOutRaw
),
CheckInOut AS (
  SELECT
    userID
    , checkTime
    , TRUNC(checkTime) dt
    , EXTRACT(HOUR FROM checkTime) h
    , COUNT(CASE EXTRACT(HOUR FROM checkTime) WHEN 11 THEN 1 ELSE NULL END) OVER (PARTITION BY TRUNC(checkTime), userID) h11
    , COUNT(CASE EXTRACT(HOUR FROM checkTime) WHEN 12 THEN 1 ELSE NULL END) OVER (PARTITION BY TRUNC(checkTime), userID) h12
  FROM
    CheckInOutTemp
),
S AS (
  SELECT
    userID
    , checkTime
    , dt
    , CASE
        WHEN h < 11 THEN 'MORN_IN'
        WHEN h = 11 THEN 'MORN_OUT'
        WHEN h11 = 1 AND h = 12 THEN 'NOON_IN'
        WHEN h = 12 THEN 'MORN_OUT'
        WHEN h < 16 THEN 'NOON_IN'
        ELSE 'NOON_OUT'
      END slot
  FROM CheckInOut
  WHERE NOT ((h = 12) AND (h12 = 2))
  UNION ALL
  SELECT
    userID
    , MIN(checkTime) checkTime
    , dt
    , 'MORN_OUT' slot
  FROM CheckInOut
  WHERE ((h = 12) AND (h12 = 2))
  GROUP BY userID, dt
  UNION ALL
  SELECT
    userID
    , MAX(checkTime) checkTime
    , dt
    , 'NOON_IN' slot
  FROM CheckInOut
  WHERE ((h = 12) AND (h12 = 2))
  GROUP BY userID, dt
)
SELECT
  userID, TO_CHAR(dt, 'YYYY-MM-DD') dt, TO_CHAR(MORN_IN, 'HH24:MI:SS') morn_in, TO_CHAR(MORN_OUT, 'HH24:MI:SS') morn_out, TO_CHAR(NOON_IN, 'HH24:MI:SS') noon_in, TO_CHAR(NOON_OUT, 'HH24:MI:SS') noon_out
FROM (SELECT * FROM S PIVOT(MAX(checkTime) FOR slot IN ('MORN_IN' morn_in, 'MORN_OUT' morn_out, 'NOON_IN' noon_in, 'NOON_OUT' noon_out))) ORDER BY userID, DT DESC
;

返回:

| USERID |         DT |  MORN_IN | MORN_OUT |  NOON_IN | NOON_OUT |
|--------|------------|----------|----------|----------|----------|
|      1 | 2014-11-04 | 08:24:49 |   (null) |   (null) |   (null) |
|      1 | 2014-11-03 | 08:15:54 |   (null) |   (null) | 16:57:00 |
|      1 | 2014-10-28 | 08:22:46 | 12:57:58 |   (null) |   (null) |
|      1 | 2014-10-24 | 08:21:38 | 12:53:06 |   (null) | 16:58:33 |
|      1 | 2014-10-22 |   (null) |   (null) |   (null) | 16:19:55 |
|      1 | 2014-10-21 | 08:26:21 |   (null) |   (null) |   (null) |
|      2 | 2014-11-04 | 08:24:49 |   (null) |   (null) |   (null) |
|      2 | 2014-11-03 | 08:15:54 |   (null) |   (null) | 16:57:00 |
|      2 | 2014-10-29 |   (null) | 11:07:58 | 12:07:58 | 16:57:58 |
|      2 | 2014-10-28 | 08:22:46 | 11:07:58 | 12:07:58 | 16:57:58 |
|      2 | 2014-10-27 | 08:22:46 | 12:07:58 | 12:57:58 | 16:57:58 |
|      2 | 2014-10-24 | 08:21:38 | 12:53:06 |   (null) | 16:58:33 |
|      2 | 2014-10-22 |   (null) |   (null) | 13:19:55 | 16:19:55 |
|      2 | 2014-10-21 | 08:26:21 |   (null) |   (null) |   (null) |
|      2 | 2014-10-20 |   (null) | 12:19:55 |   (null) | 16:19:55 |

看着

|      2 | 2014-10-20 |   (null) | 12:19:55 |   (null) | 16:19:55 |

它可能没有多大意义 - 但似乎符合规范。

SQL Fiddle