Как выбрать это время начала и продолжительность, если некоторые продолжительности больше, чем ожидалось?

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

РЕДАКТИРОВАТЬ, но не уменьшаться во времени!

Я выполняю этот запрос на SQL Server 2016. Я уже пробовал с LEAD и LAG, но не смог заставить его работать правильно.

Оригинальная таблица

| BeginTime | Duration |
------------------------
| 6:00      |       75 |
| 7:00      |       45 |
| 7:45      |       60 |
| 9:00      |       90 |
| 11:00     |       60 |
| 11:30     |       30 |
------------------------

И выход должен быть

| BeginTime | Duration |
------------------------
| 6:00      |       75 |
| 7:15      |       45 |
| 8:00      |       60 |
| 9:00      |       90 |
| 11:00     |       60 |
| 12:00     |       30 |
------------------------
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
0
0
61
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете попробовать использовать некоторую агрегатную функцию

  1. LAG оконная функция с DATEADD
  2. SUM оконная функция для накопления Duration значений.

Затем добавьте только время со значением столбца total из подзапроса.

Окончательное время добавления с MIN(BeginTime) ведьмой означает время начала.

Запрос 1:

SELECT (CASE WHEN rn = 1 THEN BeginTime
            ELSE DATEADD(MINUTE,LAG(total) OVER(ORDER BY BeginTime),MIN(BeginTime) OVER(ORDER BY BeginTime)) END) BeginTime
      ,Duration
FROM (
  SELECT *,
         SUM(Duration) OVER(ORDER BY BeginTime) total,
         ROW_NUMBER() OVER(ORDER BY BeginTime) rn,
         LAG(BeginTime) OVER(ORDER BY BeginTime) privous
  FROM T
) t1

Результаты:

|        BeginTime | Duration |
|------------------|----------|
| 06:00:00.0000000 |       75 |
| 07:15:00.0000000 |       45 |
| 08:00:00.0000000 |       60 |
| 09:00:00.0000000 |       90 |

Спасибо за ваш ответ! Я понял, что мой вопрос не был полностью объяснен, потому что время начала не должно быть перенесено назад во времени. Я отредактировал свой вопрос соответственно.

dsungaro 23.05.2019 12:58
  --Sample
  SELECT CAST('6:00' as TIME) as BeginTime, 75 as Duration
  INTO #Temp  --drop table #Temp
  UNION ALL
  SELECT '7:00',45
  UNION ALL
  SELECT '7:15',45
  UNION ALL
  SELECT '7:45',60
  UNION ALL
  SELECT '8:00',60
  UNION ALL
  SELECT '9:00',90


  --Query starts from here
   DECLARE @MinTime TIME  
  SELECT @MinTime = MIN(BeginTime) FROM #Temp

  DECLARE @MaxTime TIME  
  SELECT @MaxTime = MAX(BeginTime) FROM #Temp
  ;
  WITH A(BeginTime, Duration)
  AS
  (
     SELECT BeginTime, Duration FROM #Temp where BeginTime = @MinTime 
     UNION ALL
     SELECT DATEADD(mi,A.Duration,A.BeginTime),B.Duration
     FROM A 
     INNER JOIN #Temp as B
     ON B.BeginTime = DATEADD(mi,A.Duration,A.BeginTime)
     WHERE DATEADD(mi,A.Duration,A.BeginTime) < = @MaxTime
  )
  SELECT * FROM A

ИЗМЕНИТЬ ОТВЕТ:

В этом случае все остальные BeginTime как бы бесполезны, нужно только суммировать общее количество Duration с самым первым BeginTime:

 SELECT CAST('6:00' as TIME) as BeginTime, 75 as Duration, 1 as [Count]
  INTO #Temp  --drop table #Temp
  UNION ALL
  SELECT '7:00',45, 2
  UNION ALL
  SELECT '8:00',60, 3
  UNION ALL
  SELECT '9:00',90,4
  UNION ALL
  SELECT '10:00',60,5
  UNION ALL
  SELECT '11:00',30,6


DECLARE @MinTime Time
SELECT @MinTime =  MIN(BeginTime) FROM #Temp

SELECT BeginTime,Duration FROM #Temp WHERE BeginTime = @MinTime

UNION ALL

SELECT DATEADD(MI,SUM(B.Duration), @MinTime) as BeginTime,
       A.Duration
FROM #Temp as A
INNER JOIN #Temp as B
ON B.[Count] < A.[Count]
WHERE A.BeginTime != @MinTime
GROUP BY A.Duration, A.[Count]
ORDER BY BeginTime

Спасибо за ваш ответ! Я понял, что мой вопрос не был полностью объяснен, потому что время начала не должно быть перенесено назад во времени. Я отредактировал свой вопрос соответственно.

dsungaro 23.05.2019 12:58

@dsungaro, обновил мой ответ, вы также можете использовать сравнение BeginTime в условии самосоединения вместо дополнительного столбца Count

LONG 23.05.2019 16:38
Ответ принят как подходящий

Мой друг смог решить проблему - вот решение:

--DROP TABLE #a;
CREATE TABLE #a
(
    BeginTime DATETIME,
    Duration INT,
    BeginTimeNew DATETIME
);

INSERT INTO #a
(
    BeginTime,
    Duration
)
VALUES
('20190828  8:00:00', 75),
('20190828  9:00:00', 30),
('20190828 10:00:00', 45),
('20190828 11:00:00', 90),
('20190828 12:00:00', 75),
('20190828 13:00:00', 15),
('20190828 14:00:00', 75),
('20190828 15:00:00', 60);

SELECT *
FROM #a
ORDER BY BeginTime,
         Duration


;
WITH rownumber
AS (SELECT r = ROW_NUMBER() OVER (ORDER BY BeginTime, Duration),
           BeginTime,
           Duration
    FROM #a),
     cte
AS (SELECT r,
           OrigBeginTime = BeginTime,
           Duration,
           LV = 1,
           BeginTime,
           EndTime = DATEADD(minute, Duration, BeginTime)
    FROM rownumber
    WHERE r = 1
    UNION ALL
    SELECT a.r,
           a.BeginTime,
           a.Duration,
           b.LV + 1,
           BeginTime = IIF(b.EndTime >= a.BeginTime, b.EndTime, a.BeginTime),
           EndTime = DATEADD(minute, a.Duration, IIF(b.EndTime >= a.BeginTime, b.EndTime, a.BeginTime))
    FROM rownumber a
        INNER JOIN cte b
            ON a.r = b.r + 1)
UPDATE a
SET BeginTimeNew = b.BeginTime
FROM #a a
    INNER JOIN cte b
        ON a.BeginTime = b.OrigBeginTime
           AND a.Duration = b.Duration
OPTION (MAXRECURSION 0);

SELECT *
FROM #a
ORDER BY BeginTime,
         Duration

Другие вопросы по теме