sql时间表按天计算一周

时间:2011-08-16 16:17:49

标签: sql sql-server sql-server-2005

我的表看起来像这样:

select clocktime, for_UID, in1_out0 from timeclockentries

clocktime                   for_UID    in1_out0
2011-08-07 15:13:58.390 user193    1
2011-08-07 21:09:45.093 user193    0
2011-08-09 14:10:00.000 user193    1
2011-08-09 20:10:00.000 user193    0

我希望结果看起来像(假设周开始是星期六),由名为'day1','day2'等的COLUMNS分隔....(但为了便于阅读,我用换行符输入了它们) :

day1                       day2                       day3
1900-01-01 00:00:00.000    1900-01-01 05:55:46.700    1900-01-01 00:00:00.000   

day4                       day5                       day6
1900-01-01 06:00:00.000    1900-01-01 00:00:00.000    1900-01-01 00:00:00.000

day7
1900-01-01 00:00:00.000

(我正在使用sql2005)

下面是我正在使用的一天:

CREATE PROCEDURE [dbo].[sp_gethoursbyday]
  @whichforUID varchar(20),
  @whichdate datetime
AS
BEGIN

;WITH CTE as(
SELECT 
    DENSE_RANK() over (Partition by for_UID , in1_out0  Order by clocktime) id,
    clocktime,
    for_UID,
    in1_out0

FROM 
    kdhcastle.dbo.timeclockentries tc
WHERE 
         tc.for_UID = @whichforUID 
and month(tc.[clocktime]) = month(@whichdate)
and day(tc.[clocktime]) = day(@whichdate)
and year(tc.[clocktime]) = year(@whichdate)

    )
SELECT
     Cast(cast(sum(
        cast(outTime.clocktime as float) - cast(inTime.clocktime as float)
        )as datetime) as datetime) as 'hoursbydy'
FROM 
     CTE inTime
     INNER JOIN CTE outTime
     ON inTime.for_UID = outTime.for_UID
         AND inTime.id = outTime.id
        AND inTime.in1_out0 = 1
        and outTime.in1_out0 = 0

    END

2 个答案:

答案 0 :(得分:2)

SELECT
  SUM(CASE WHEN DayOfWeek = 1 THEN Duration ELSE 0 END)    AS Day1,
  SUM(CASE WHEN DayOfWeek = 2 THEN Duration ELSE 0 END)    AS Day2,
  SUM(CASE WHEN DayOfWeek = 3 THEN Duration ELSE 0 END)    AS Day3,
  SUM(CASE WHEN DayOfWeek = 4 THEN Duration ELSE 0 END)    AS Day4,
  SUM(CASE WHEN DayOfWeek = 5 THEN Duration ELSE 0 END)    AS Day5,
  SUM(CASE WHEN DayOfWeek = 6 THEN Duration ELSE 0 END)    AS Day6,
  SUM(CASE WHEN DayOfWeek = 7 THEN Duration ELSE 0 END)    AS Day7
FROM
(
  SELECT
    DATEDIFF(DAY, '2011 Jan 01', clocktime) % 7 + 1  AS DayOfWeek,
    CAST(MAX(clocktime) - MIN(clocktime) AS FLOAT)   AS Duration
  FROM
    yourTable
  GROUP BY
    for_UID,
    DATEDIFF(DAY, '2011 Jan 01', clocktime)
)
  AS [data]

答案 1 :(得分:0)

这更详细但我的重点是(a)避免重复表达式和(b)模拟要输入到存储过程的所有输入参数,以便在所需的用户/日期过滤结果。请注意,@whichdate参数会在午夜回归到前一个星期六,无论一周中的哪一天或与之相关的时间。

输入参数:

DECLARE @whichdate DATETIME;
SET @whichdate = '2011-08-08T12:34:00';

DECLARE @whichforUID VARCHAR(32);
SET @whichforUID = 'user193';

正文(只需注释掉DECLARE @t / INSERT @t行,并将第一个CTE中的@t更改为实际表名:

SET @whichdate = DATEADD(DAY, -DATEPART(WEEKDAY, @whichdate), @whichdate);
SET @whichdate = DATEADD(DAY, 0, DATEDIFF(DAY, 0, @whichdate));

DECLARE @t TABLE(clocktime DATETIME, for_UID VARCHAR(32), in1_out0 BIT);

INSERT @t SELECT '2011-08-07 15:13:58.390','user193',1
UNION ALL SELECT '2011-08-07 21:09:45.093','user193',0
UNION ALL SELECT '2011-08-09 14:10:00.000','user193',1
UNION ALL SELECT '2011-08-09 20:10:00.000','user193',0;

WITH s(dw, ct, in1_out0) AS
(
    SELECT 1 + (DATEDIFF(DAY, '2011-01-01', clocktime) % 7), 
        clocktime, in1_out0 FROM @t
        where for_UID = @whichforUID
        AND clocktime >= @whichdate
        AND clocktime < DATEADD(DAY, 7, @whichdate)
),
d(dw, min_ct, max_ct) AS 
(
    SELECT dw, 
        MIN(CASE WHEN in1_out0 = 1 THEN ct ELSE NULL END),
        MAX(CASE WHEN in1_out0 = 0 THEN ct ELSE NULL END)
    FROM s GROUP BY dw
),
x AS 
(
    SELECT d = DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, min_ct, max_ct), 0), 
        dw FROM d
),
pvt AS (
    SELECT * FROM x PIVOT
    (MAX(d) FOR dw IN ([1],[2],[3],[4],[5],[6],[7])) AS p
)
SELECT
    day1 = COALESCE([1], '19000101'),
    day2 = COALESCE([2], '19000101'),
    day3 = COALESCE([3], '19000101'),
    day4 = COALESCE([4], '19000101'),
    day5 = COALESCE([5], '19000101'),
    day6 = COALESCE([6], '19000101'),
    day7 = COALESCE([7], '19000101')
FROM pvt;