Скрипт T-SQL - проблемы логики с временной шкалой - PullRequest
5 голосов
/ 17 ноября 2010

Две временные таблицы создаются и затем загружаются ... Вот схема.

Create table #SH ([date] datetime,
        sched_id int,
        agent_id int)

Create table #SD (sched_id int,
        start_minute int,
        length int,
        exception_code int)

(К сожалению, я не могу изменить схему и дизайн, обе временные таблицы загружаются из плоских файлов. При необходимости я могу представить и загрузить новые временные таблицы).

Немного предыстории - Таблица заголовков #SH содержит расписание лиц в виде «Start_minute» и идет за «schedule_length» в минутах. Например, если бы стартовая минута и продолжительность расписания были равны 480, это было бы читать как 8:00 (8:00 = 480 минута) и продолжалось до 16:00 (480 минут спустя, 4:00 = 960 минута)

Таблица #SD содержит исключения для заголовка. В приведенном выше примере у человека, вероятно, будет исключение для обеда, которое будет start_minute = 720 и длина 30 (12:00 - 12:30).

Дата и agent_id - единственное, что меня интересует из #SH, информация об исключениях в #sd - это то, что меня интересует.

Этот запрос работает:

Select [date],#sd.start_minute,#sd.length,#sd.start_minute + #sd.length as 'end_minute',agent_id
from #SH 
inner join #SD on #SD.sched_id = #sh.sched_id

* end_minute - это, в конечном счете, вычисленное значение start + length = end

Это возвращает что-то вроде:

   Date     Start  length   end

1 2010-11-11 600    30  630

2 2010-11-11 630    40  670

3 2010-11-11 750    15  765

4 2010-11-11 800    40  840

Теперь я хотел бы сказать, что все кончено и ушло ... но проблемы с вводом данных существуют. В строках 1 и 2 время окончания строки 1 совпадает со временем начала в строке 2 и должно быть объединено, чтобы мои результаты выглядели так:

Date     Start  length     end

1 2010-11-11 600    70  670

2 2010-11-11 750    15  765

3 2010-11-11 800    40  840

Есть идеи, как построить эту логику, чтобы я вернул 3 строки вместо 4? Сейчас я работаю над присоединением таблицы к себе на # sd1.start + # sd1.length = # sd2.start.

И, что еще больше усложнит ... приведенный выше пример состоял из 2 строк, которые нужно было объединить. Я натолкнулся на запись, в которой было 30 записей по 1 минуте подряд, которые мне нужно будет сделать в одной записи. К счастью, они не могут перекрываться (у вас не будет двух записей, занимающих одни и те же минуты), но я не думаю, что оператор соединения, который я рассматриваю выше, будет работать для этого.

Ответы [ 2 ]

2 голосов
/ 17 ноября 2010

Нет необходимости в CTE, все, что вам нужно, это вспомогательный стол. Создайте его один раз, вот так:

Create Table DayMinute(Minute Integer)
Declare @M Integer
Set @M = 1
While (@M <= 24*60)
Begin
  Insert Into DayMinute(Minute) Values(@M)
  Set @M = @M + 1
End

Тогда все, что вам нужно, это немного хитрости:

Select 
  DM.Minute,
  SD.Sched_ID
Into #MinutesWithException
From 
  DayMinute As DM
  Inner Join #SD As SD
    On DM.Minute Between SD.Start_Minute And SD.Start_Minute + Length

Select
  MWE.Sched_ID,
  SH.[Date],
  SH.Agent_ID,
  [Start_Minute] = MWE.Minute,
  [End_Minute] = (Select Min(Last.Minute) -- First one to have no successor
                  From #MinutesWithException As Last
                  Where Last.Sched_ID = MWE.Sched_ID
                    And Last.Minute > MWE.Minute
                    And Not Exists(Select *
                                   From #MinutesWithException As Next
                                   Where Next.Sched_ID = MWE.Sched_iD
                                     And Next.Minute = Last.Minute + 1))
From 
  #MinutesWithException As MWE
  Inner Join #SH As SH
    On MWE.Sched_ID = SH.Sched_ID
Where
  Not Exists(Select * -- All those without predecessor
             From #MinutesWithException As Previous
             Where Previous.Sched_ID = MWE.Sched_ID
               And Previous.Minute = MWE.Minute - 1)

Помните, что многие проблемы SQL можно решить, перефразировав их. Не спрашивайте «у каких диапазонов нет пропуска», спрашивайте «у каких минут есть интервал» Остальное следует оттуда.

1 голос
/ 17 ноября 2010

Если вы используете рекурсивный CTE для объединения результатов вашего запроса, вы можете объединить в цепочку до 32767 записей.Вы можете рассмотреть этот подход, если не думаете, что когда-нибудь приблизитесь к этой сумме.

Я создал рабочий пример, потому что я не был уверен.Ваша группировка будет другой, но это общая идея:

CREATE TABLE times
(
[Date] datetime,
[start] int,
[length] int,
[end] int
)
INSERT INTO times([Date], [Start], [length], [End])
VALUES ('11/11/2010',600,30,630)
INSERT INTO times([Date], [Start], [length], [End])
VALUES ('11/11/2010',630,40,670)
INSERT INTO times([Date], [Start], [length], [End])
VALUES ('11/11/2010',750,15,765)
INSERT INTO times([Date], [Start], [length], [End])
VALUES ('11/11/2010',800,40,840)

;WITH chaintimes AS
(
    SELECT t1.Date, t1.start, t1.length, t1.[end]
    FROM times t1 LEFT JOIN times t2 ON t1.start = t2.[end]
    WHERE t2.[end] IS NULL
    UNION ALL
    SELECT times.Date, chaintimes.start, chaintimes.length + times.length AS length, times.[end]
    FROM times INNER JOIN chaintimes ON times.start = chaintimes.[end]
)
, start_maxlength AS
(
    SELECT date, start, max(length) AS maxlength
    FROM chaintimes
    group by date, start
)
SELECT * FROM chaintimes ct
INNER JOIN start_maxlength ml
ON ct.Date = ml.Date AND ct.start = ml.start AND ct.length = ml.maxlength
...