Сводная таблица, показывающая количество «открытых» записей по часам - PullRequest
1 голос
/ 14 октября 2019

У меня фактически есть таблица с двумя важными полями. ReadyDate и CompleteDate.

Я хочу, чтобы мои выходные данные давали мне 24 столбца, соответствующих часу дня, в каждом из которых указывалось количество записей, которые все еще были "открыты" (определяется как ReadyDate до концачас, но CompleteDate после окончания часа) в течение этого часового часа.

Таким образом, хитрость заключается в том, что одна запись может появляться в ноль или более столбцов. То, что было ReadyDate в 6:05 утра и CompleteDate 9:17 утра, появилось бы в столбцах 6:00, 7:00 и 8:00.

Так что, если в таблице есть следующие записи

10-14-2019 06:05   10-14-2019 06:10    (this will populate no columns)
10-14-2019 07:12   10-14-2019 09:30    (this will populate the 7:00 hour and 8:00 hour)
10-14-2019 10:02   10-14-2019 13:55    (this will populate the 10:00 hour, 11:00, 12:00)
10-14-2019 12:50   10-14-2019 15:30    (this will populate the 12:00, 13:00, 14:00)

Я ожидаю, что мой вывод будет иметь 24 столбца со следующими числами 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0

Я не знаю, как поступить. Любые идеи будут оценены

Ответы [ 3 ]

2 голосов
/ 14 октября 2019

ИСПРАВЛЕНО ДЛЯ РЕДАКТИРОВАНИЯ СДВИГА НА 1 ЧАС

Вот опция PIVOT, которая использует специальную таблицу подсчета.

перевернутая полночь учитывается.

Непонятно, хотите ли вы строки по дате. Если нет, то это будет небольшим вопросом для удаления.

Пример

;with cte1 as (
    Select Date  = convert(date,D) 
          ,Item  = datepart(hour,D)
          ,Value = 1
     From  YourTable A
     Cross Apply (
                    Select Top (DateDiff(HOUR,ReadyDate,CompleteDate)+0) 
                           D=DateAdd(HOUR,-1+Row_Number() Over (Order By (Select Null)),ReadyDate) 
                     From  master..spt_values n1,master..spt_values n2
                  ) B
),  cte2 as ( 
    Select Date
          ,B.Item 
          ,B.Value
     From  (Select distinct Date from cte1 ) a
     Cross Join (Select Top 24 Item=-1+Row_Number() Over (Order By (Select NULL)),Value=0 From master..spt_values n1 ) B
)
Select *
 From  (Select * from cte1
        Union All
        Select * from cte2
        ) src
 Pivot (sum(Value) for Item in ([0] ,[1] ,[2] ,[3] ,[4] ,[5] ,[6] ,[7] ,[8] ,[9] ,[10],[11],
                                [12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23]) ) pvt

Возвращает

enter image description here

1 голос
/ 14 октября 2019

Это не самая красивая, но она работает, как вы объяснили. Я хотел бы увидеть более элегантное решение, если у кого-то есть.

DECLARE @t TABLE
(
    date1 DATETIME NOT NULL,
    date2 DATETIME NOT NULL
);

INSERT INTO @t
(
    date1,
    date2
)
VALUES
('10-14-2019 06:05', '10-14-2019 06:10'),
('10-14-2019 07:12', '10-14-2019 09:30'),
('10-14-2019 10:02', '10-14-2019 13:55'),
('10-14-2019 12:50', '10-14-2019 15:30');

SELECT SUM(t.[0]) AS [0],
       SUM(t.[1]) AS [1],
       SUM(t.[2]) AS [2],
       SUM(t.[3]) AS [3],
       SUM(t.[4]) AS [4],
       SUM(t.[5]) AS [5],
       SUM(t.[6]) AS [6],
       SUM(t.[7]) AS [7],
       SUM(t.[8]) AS [8],
       SUM(t.[9]) AS [9],
       SUM(t.[10]) AS [10],
       SUM(t.[11]) AS [11],
       SUM(t.[12]) AS [12],
       SUM(t.[13]) AS [13],
       SUM(t.[14]) AS [14],
       SUM(t.[15]) AS [15],
       SUM(t.[16]) AS [16],
       SUM(t.[17]) AS [17],
       SUM(t.[18]) AS [18],
       SUM(t.[19]) AS [19],
       SUM(t.[20]) AS [20],
       SUM(t.[21]) AS [21],
       SUM(t.[22]) AS [22],
       SUM(t.[23]) AS [23]
FROM
(
    SELECT id,
           date1,
           date2,
           CASE
               WHEN 0
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [0],
           CASE
               WHEN 1
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [1],
           CASE
               WHEN 2
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [2],
           CASE
               WHEN 3
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [3],
           CASE
               WHEN 4
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [4],
           CASE
               WHEN 5
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [5],
           CASE
               WHEN 6
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [6],
           CASE
               WHEN 7
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [7],
           CASE
               WHEN 8
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [8],
           CASE
               WHEN 9
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [9],
           CASE
               WHEN 10
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [10],
           CASE
               WHEN 11
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [11],
           CASE
               WHEN 12
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [12],
           CASE
               WHEN 13
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [13],
           CASE
               WHEN 14
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [14],
           CASE
               WHEN 15
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [15],
           CASE
               WHEN 16
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [16],
           CASE
               WHEN 17
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [17],
           CASE
               WHEN 18
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [18],
           CASE
               WHEN 19
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [19],
           CASE
               WHEN 20
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [20],
           CASE
               WHEN 21
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [21],
           CASE
               WHEN 22
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [22],
           CASE
               WHEN 23
                    BETWEEN DATEPART(HOUR, date1) AND DATEPART(HOUR, date2) - 1 THEN
                   1
               ELSE
                   0
           END AS [23]
    FROM @t
) t;

Вывод:

0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  19  20  21  22  23
0   0   0   0   0   0   0   1   1   0   1   1   2   1   1   0   0   0   0   0   0   0   0   0
0 голосов
/ 14 октября 2019

Есть несколько вопросов о предоставленной вами выборке данных. Не совсем понятно, как выбран каждый час. Является ли час выбранным, если количество минут, в течение которых элемент был активен, превышает некоторое число? Существует также возможная проблема с CompletedDate на следующий день. В любом случае вот еще один пример, как этого добиться. Вам придется повозиться с часовой логикой, чтобы получить нужный ответ.

DECLARE @data Table
(
    id int identity(1,1)
    ,ReadyDate datetime
    ,CompletedDate datetime
    ,foo varchar(500)
)
INSERT INTO @data
VALUES

('10-14-2019 06:05','10-14-2019 06:10','(this will populate no columns)')
,('10-14-2019 07:12','10-14-2019 09:30','(this will populate the 7:00 hour and 8:00 hour)')
,('10-14-2019 10:02','10-14-2019 13:55','(this will populate the 10:00 hour, 11:00, 12:00)')
,('10-14-2019 12:50','10-14-2019 15:30','(this will populate the 12:00, 13:00, 14:00)') 

;
;WITH Numbers AS
(
    SELECT 1 AS Number
    UNION ALL
    SELECT Number+1
        FROM Numbers 
        WHERE Number < 24
)
,src
as (
Select *, 
    flag = CASE WHEN Number >= DATEPART(hour, ReadyDate) AND Number < DATEPART(hour, ReadyDate) + DateDiff(hour, ReadyDate, CompletedDate) THEN 1 ELSE 0 END 
from @Data
    CROSS APPLY Numbers
)
Select * 
from src
    PIVOT 
    (
        max(flag) for number in ([1],[2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24])
    ) as ptable
...