Нарастающая со временем (не перекрывающаяся) - техника? - PullRequest
2 голосов
/ 13 мая 2011

Я пытаюсь найти лучший способ сделать Crystal Report (кто-то еще) ... Добавить непересекающееся время в группах.Это, очевидно, давняя проблема ... Существует ли метод получения

  • Скорректированного времени (начало / конец) для каждой записи, чтобы удалить общее время / время наложения,
  • в подгруппах
  • - используя прямой SQL (хотя я нахожу, что могу сделать CTE)

Предположим, что начальный упорядочен для времени начала (и / или группы, подгруппы) иStart и End являются отдельными полями.

Типичный графический пример:

Group 1
  SubGroup A
    Tkt 1    |--start&end---|                      "16"
    Tkt 2        |----tart&end----|                "18"
    Tkt 3          |--art&end---|                  "14"
    Tkt 4                            |--S & E -|   "11"

  SubGroup B
    Tkt 5  |-S&E-|                                  "7" 
    Tkt 6          |-S&E-|                          "7" 
    Tkt 7            |-S&E-|                        "7"  
    ...

(equiv adjusted start/end w/in sub-group):
Group 1
  SubGroup A                         (  w/ "elapsed time" of "33"   )
    Tkt 1    |--start&end---|         <- Regular             "16"
    Tkt 2                   |-----|   <- Adjusted "start"     "6"
    Tkt 3                         |   <- Adjusted "start" & "end"   "0"
    Tkt 4                            |--S & E -|  <- Regular "11"

  SubGroup B                         ( w/ "elapsed time"  of "17"   )
    Tkt 5  |-S&E-|                    <- Regular              "7"  
    Tkt 6          |-S&E-|            <- Regular (no overlap) "7"
    Tkt 7                |-|          <- Adjusted "Start"     "3"
    ...

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

В отчете они выполняют несколько формул для каждой записи, сравнивая две переменные, заданные для первой записи в группе, затем устанавливая / обновляя значения для AdjustedStart, AdjustedEnd на основе текущей записи и передаваяAdjustedStart, AdjustedEnd в другую формулу для вычисления разницы во времени, которая будет суммирована позже.Текущий метод медленный, и я не могу сделать изящную перекрестную таблицу, которая желательна.

Я думаю / надеюсь, что это было решено только в SQL, так как мы не можем поместить какой-либо процесс, временные таблицы и т. д. на сервере БД.Я пытаюсь выяснить способ w / CTE и (пере) проклятия, используя Group / SubGroup в качестве происхождения и CASE для сравнения текущих значений с последними родительскими значениями.Звучит ли это как колокольчик или звучит правдоподобно?

Способностей Кристалла много, но, похоже, он не предназначен для этого.

Марк

Ответы [ 2 ]

0 голосов
/ 11 января 2013

Я ценю, что вы задали этот вопрос очень давно, но он меня заинтересовал, поэтому я провел небольшое исследование и нашел решение Джеффа Модена; он написал статью о группировании островов дат, которые вы можете найти здесь: Группа островов смежных дат (требуется регистрация, но регистрация бесплатна).

Я предположил, что у вас есть таблица со строками для каждого дня в подгруппе, поэтому есть 16 строк для "Tkt1", 18 для "Tkt2" и т. Д. Если это не так, и у вас есть только start и даты окончания каждого «Tkt», вам придется использовать таблицу Calendar для экстраполяции строк для каждого диапазона.

Решение Джеффа использует трюк ROW_NUMBER и DATEDIFF для группировки островов дат.

WITH Grouped_Dates AS
( -- Find the unique dates and assign them to a group.
  -- The group looks like a date but the date means nothing except that adjacent
  -- dates will be a part of the same group.
 SELECT group_name,
        unique_date = tkt_date,
        date_group  = DATEADD(dd, -ROW_NUMBER() OVER (PARTITION BY group_name ORDER BY group_name, tkt_date), tkt_date)
  FROM t
  GROUP BY group_name, tkt_date
)
-- Now, if we find the MIN and MAX date for each date_group, we'll have the
-- Start and End dates of each group of contiguous daes.  While we're at it,
-- we can also figure out how many days are in each range of days.
SELECT group_name,
       start_date = MIN(unique_date),
       end_date   = MAX(unique_date),
       days       = DATEDIFF(dd,MIN(unique_date),MAX(unique_date))+1
FROM Grouped_Dates
GROUP BY group_name, date_group
ORDER BY group_name, start_date

Результат этого запроса

group_name  start_date  end_date    days
----------  ----------  ----------  ----
Group1      2012-01-01  2012-01-22    22
Group1      2012-01-24  2012-02-03    11
Group2      2012-01-09  2012-01-15     7
Group2      2012-01-18  2012-01-27    10

Я создал SQL Fiddle с примерами данных на основе вашего вопроса.

Затем вы можете суммировать каждую группу, чтобы дать общее время, потраченное.

0 голосов
/ 13 мая 2011

Я делаю это с макушки головы ...

SELECT
    CUR.subgroup,
    CUR.ticket,
    COALESCE(MAX(PARENT.end_time), CUR.start_time) AS start_time,
    CASE
        WHEN CUR.end_time < MAX(PARENT.end_time) THEN MAX(PARENT.end_time)
        ELSE CUR.end_time
    END
FROM
    My_Table CUR
LEFT OUTER JOIN My_Table PARENT ON
    PARENT.start_time <= CUR.start_time AND
    PARENT.end_time > CUR.start_time AND
    PARENT.ticket <> CUR.ticket AND
    PARENT.subgroup = CUR.subgroup
GROUP BY
    CUR.subgroup,
    CUR.ticket,
    CUR.start_time,
    CUR.end_time
...