Это более многословно, но я сосредоточился (а) на том, чтобы избежать повторения выражений и (б) на моделировании всех входных параметров, предназначенных для передачи в хранимую процедуру, чтобы результаты фильтровались по желаемому пользователю / дате.Обратите внимание, что параметр @whichdate возвращается к предыдущей субботе в полночь, независимо от того, какой это день недели или какое время связано с ним.
Входные параметры:
DECLARE @whichdate DATETIME;
SET @whichdate = '2011-08-08T12:34:00';
DECLARE @whichforUID VARCHAR(32);
SET @whichforUID = 'user193';
Body (просто закомментируйте строки DECLARE @t / INSERT @t и замените @t в первом CTE на реальное имя таблицы:
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;