ASCI диаграмма дискретных единиц времени - PullRequest
0 голосов
/ 16 апреля 2020

Скрипка: http://sqlfiddle.com/#! 18 / d7d80 / 6

Данные:

CREATE TABLE schedule
    ([dte] date, [tme] time, [wkd] int);

INSERT INTO schedule
    ([dte], [tme], [wkd])
VALUES
    ('2020/01/01', '17:30', 15),
    ('2020/01/01', '18:00', 15),
    ('2020/01/01', '18:15', 15),
    ('2020/01/02', '17:30', 30),
    ('2020/01/02', '18:00', 30),
    ('2020/01/03', '17:30', 120),
    ('2020/01/04', '17:45', 45),
    ('2020/01/05', '17:45', 30),
    ('2020/01/06', '17:45', 15),
    ('2020/01/07', '18:00', 30);

Таблица состоит из трех столбцов: дата, время и отработанные минуты. Время и минуты работают всегда с шагом 15 минут (полный час, 15 минут, полчаса, 45 минут).

Проблема:

Я хотел бы показать простой график использования ASCI, показывающий рабочие и свободные периоды. Например, для приведенных выше данных это может выглядеть примерно так:

01/01| X XX
01/02| XXXX
01/03| XXXX
01/04|  XXX
01/05|  XX
01/06|  X
01/07|   XX

Попытка решения:

Я начал со следующего запроса:

with cte as (SELECT dte,
       tme,
       convert(time,DATEADD(MINUTE, wkd, tme)) as fns
FROM   schedule)

SELECT dte,
       max(case when CONVERT (TIME,{t '17:30:00'}) >= tme 
                 and CONVERT (TIME,{t '17:45:00'}) <= fns then 'x' else null end),
       max(case when CONVERT (TIME,{t '17:45:00'}) >= tme
                 and CONVERT (TIME,{t '18:00:00'}) <= fns then 'x' else null end),
       max(case when CONVERT (TIME,{t '18:00:00'}) >= tme
                 and CONVERT (TIME,{t '18:15:00'}) <= fns then 'x' else null end),
       max(case when CONVERT (TIME,{t '18:15:00'}) >= tme
                 and CONVERT (TIME,{t '18:30:00'}) <= fns then 'x' else null end)
FROM cte
GROUP BY dte

Хотя это, кажется, работает, я уже вижу, что этот подход будет действительно неловким, если мне когда-либо придется изменить период времени, на который я смотрю, или увеличить его с одного часа до двух или более часов.

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

Ответы [ 2 ]

1 голос
/ 16 апреля 2020

Аналогично вашему запросу, используя условный оператор case с max() aggregate. Я использую подчеркивание вместо пробела, чтобы легче было проверить результат

SELECT dte,
       MAX (CASE WHEN '17:00' >= s.tme AND '17:00' < DATEADD(MINUTE, s.wkd, s.tme) THEN 'X' ELSE '_' END) +
       MAX (CASE WHEN '17:15' >= s.tme AND '17:15' < DATEADD(MINUTE, s.wkd, s.tme) THEN 'X' ELSE '_' END) +
       MAX (CASE WHEN '17:30' >= s.tme AND '17:30' < DATEADD(MINUTE, s.wkd, s.tme) THEN 'X' ELSE '_' END) +
       MAX (CASE WHEN '17:45' >= s.tme AND '17:45' < DATEADD(MINUTE, s.wkd, s.tme) THEN 'X' ELSE '_' END) +
       MAX (CASE WHEN '18:00' >= s.tme AND '18:00' < DATEADD(MINUTE, s.wkd, s.tme) THEN 'X' ELSE '_' END) +
       MAX (CASE WHEN '18:15' >= s.tme AND '18:15' < DATEADD(MINUTE, s.wkd, s.tme) THEN 'X' ELSE '_' END) +
       MAX (CASE WHEN '18:30' >= s.tme AND '18:30' < DATEADD(MINUTE, s.wkd, s.tme) THEN 'X' ELSE '_' END) 
FROM   schedule s
GROUP BY dte
0 голосов
/ 16 апреля 2020

Я бы предложил использовать какой-либо шаблон или процедуру для генерации вашего запроса. Из этого вопроса не ясно, выполняете ли вы запрос напрямую (вручную) на сервере sql или если какое-то приложение выполняет его для базы данных сервера sql. В первом случае вы можете создать хранимую процедуру для генерации запроса для вас на основе интервала времени (в вашем случае 15 минут). Во втором случае вы можете создать бэкэнд любого приложения, которое вы используете, сгенерировать запрос.

Общий случай в псевдокоде:

// inputs

timeUnit = 15 min
rangeStart = 17:30:00
rangeEnd = 18:30:00

// algorithm
discreteTimes = toDiscreteTimes(rangeStart, rangeEnd, timeUnit) // calculate discrete times between rangeStart and rangeEnd, so in your case 17:30, 17:45, ..., 18:30

query = "..." // up to the start of your case statements
for (i = 1; i < discreteTimes.maxIndex; i++) {
    query += caseStatement(discreteTimes[i-1], discreteTimes[i]) // generate your case statement with these two times
}

query += "..." // the rest of the query after the case statements
...