Как создать время на основе интервала и времени начала? - PullRequest
1 голос
/ 12 июня 2019

Я выполняю некоторую оптимизацию планирования в моей базе данных.

Для расписания работ многие записи выглядят так:

Time    NextRunTime
Every 3 hours   2019-06-03 10:00:00
Every 3 hours   2019-05-28 20:00:00
Every 4 hours   2017-07-31 18:00:00
Every 1 hours   2019-06-03 14:00:00
Every 4 hours   2017-06-08 16:00:00

Что такое эффективный способ разделения "каждых" записей на отдельные записи в течение 24 часов?

Например, для первой записи (каждые 3 часа с 10:00) мне нужно вставить следующее в таблицу:

Time
13:00:00
16:00:00
19:00:00
22:00:00
01:00:00
04:00:00
07:00:00
10:00:00

Мне нужно повторить это для каждой записи в первойтаблица со словом «каждый».

Кто-нибудь может помочь?

Ответы [ 3 ]

1 голос
/ 12 июня 2019

Я всегда думал, что рекурсивный cte - хороший способ решить ваш запрос:

-- the sample data
declare @data as table (freq varchar(100), tmst datetime, each_ int)
insert into @data
select s.freq,s.tmst,
  convert(int,replace(replace(freq,'Every ',''),' hours','')) as each_
from (
  select 'Every 4 hours' as freq, convert(datetime,'2019-06-02 10:00:00') as tmst union all
  select 'Every 3 hours' as freq, convert(datetime,'2019-06-02 11:00:00') as tmst union all
  select 'Every 2 hours' as freq, convert(datetime,'2019-06-02 10:00:00') as tmst
) s

-- the query
;with cte as ( 
  select freq, tmst, each_, null t1 from @data
  union all
  select freq, tmst, each_, isnull(t1,datepart(hour,tmst)) + each_
  from cte
  where isnull(t1,datepart(hour,tmst)) + each_ <= 23
)
select freq,
  isnull(convert(datetime, convert(varchar(8),tmst,112) + ' ' + (convert(varchar(100),t1) + ':00:00' ), 120),tmst)
from cte
order by 1, 2

В этой второй версии вы можете получить все диапазоны от 0 до 23 (в предыдущем примере вы получили только от начальной точки до 23)

-- the query
;with findfirst as ( 
  select freq, tmst, datepart(hour,tmst) as fhour, datepart(hour,tmst) as init, each_ from @data
  union all
  select freq, tmst, fhour, init - each_, each_ from findfirst where init - each_ >= 0
),
cte as ( 
  select min(init) as init, freq, tmst, each_, fhour from findfirst group by freq, tmst, each_, fhour
  union all
  select init + each_, freq, tmst, each_, fhour from cte where init + each_ <= 23
)
select freq,tmst,convert(time, right('0' + convert(varchar(2),init), 2) + ':00:00')
from cte order by freq,init,each_

Не забудьте продолжать использовать таблицу @data.

Выход:

output query 2

1 голос
/ 12 июня 2019

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

DECLARE @starttime DATETIME = '2019-06-03 10:00:00', @hours INT = 3;

SELECT t.N, Tm = CAST(DATEADD(HOUR,t.N*3,@startTime) AS TIME)
FROM
(
  SELECT TOP (24/@hours) ROW_NUMBER() OVER (ORDER BY (SELECT 1)) 
  FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS a(x),
       (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS b(x)
) AS t(N);

Возвращает:

N       Tm
------- ----------------
1       13:00:00.0000000
2       16:00:00.0000000
3       19:00:00.0000000
4       22:00:00.0000000
5       01:00:00.0000000
6       04:00:00.0000000
7       07:00:00.0000000
8       10:00:00.0000000

Теперь для некоторых примеров данных и идентификатора записи (названного "someId")") поэтому мы можем рассчитать это для всех строк в вашей таблице.

-- Sample Data
DECLARE @yourTable TABLE (someId INT IDENTITY PRIMARY KEY, freq INT, NextRunTime DATETIME);
INSERT @yourTable(freq, NextRunTime) VALUES (3, '2019-06-03 10:00:00'),
                 (3, '2019-05-28 20:00:00'),(4, '2017-07-31 18:00:00'),
                 (1, '2019-06-03 14:00:00'),(4, '2017-06-08 16:00:00');

-- Solution                 
SELECT yt.someId, f.Tm 
FROM   @yourTable AS yt
CROSS APPLY
(
  SELECT t.N, CAST(DATEADD(HOUR,t.N*yt.freq,yt.NextRunTime) AS TIME)
  FROM
  (
    SELECT TOP (24/yt.freq) ROW_NUMBER() OVER (ORDER BY (SELECT 1)) 
    FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS a(x),
         (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS b(x)
  ) AS t(N)
) AS f(N,Tm);

Возвращает:

someId      Tm
----------- ----------------
1           13:00:00.0000000
1           16:00:00.0000000
1           19:00:00.0000000
1           22:00:00.0000000
1           01:00:00.0000000
1           04:00:00.0000000
1           07:00:00.0000000
1           10:00:00.0000000
2           23:00:00.0000000
2           02:00:00.0000000
2           05:00:00.0000000
2           08:00:00.0000000
2           11:00:00.0000000
2           14:00:00.0000000
2           17:00:00.0000000
2           20:00:00.0000000
3           22:00:00.0000000
3           02:00:00.0000000
3           06:00:00.0000000
3           10:00:00.0000000
3           14:00:00.0000000
3           18:00:00.0000000
4           15:00:00.0000000
4           16:00:00.0000000
4           17:00:00.0000000
4           18:00:00.0000000
4           19:00:00.0000000
4           20:00:00.0000000
4           21:00:00.0000000
4           22:00:00.0000000
4           23:00:00.0000000
4           00:00:00.0000000
4           01:00:00.0000000
4           02:00:00.0000000
4           03:00:00.0000000
4           04:00:00.0000000
4           05:00:00.0000000
4           06:00:00.0000000
4           07:00:00.0000000
4           08:00:00.0000000
4           09:00:00.0000000
4           10:00:00.0000000
4           11:00:00.0000000
4           12:00:00.0000000
4           13:00:00.0000000
4           14:00:00.0000000
5           20:00:00.0000000
5           00:00:00.0000000
5           04:00:00.0000000
5           08:00:00.0000000
5           12:00:00.0000000
5           16:00:00.0000000
0 голосов
/ 12 июня 2019

Сначала удалите все временные таблицы, которые имеют имена временных таблиц, которые вы создадите:

IF OBJECT_ID(N'tempdb..#Interval', N'U') IS NOT NULL DROP TABLE #Interval
GO
IF OBJECT_ID(N'tempdb..#Interval2', N'U') IS NOT NULL DROP TABLE #Interval2
GO
IF OBJECT_ID(N'tempdb..#Runstart', N'U') IS NOT NULL DROP TABLE #Runstart
GO

Затем создайте и вставьте данные в свои временные таблицы:

CREATE TABLE #Interval
(
_Time NVARCHAR(13),
NextRunTime DATETIME
)
GO
INSERT INTO #Interval VALUES ('Every 3 hours','2019-06-03 10:00:00')
INSERT INTO #Interval VALUES ('Every 3 hours','2019-05-28 20:00:00')
INSERT INTO #Interval VALUES ('Every 4 hours','2017-07-31 18:00:00')
INSERT INTO #Interval VALUES ('Every 1 hours','2019-06-03 14:00:00')
INSERT INTO #Interval VALUES ('Every 4 hours','2017-06-08 16:00:00')
GO

CREATE TABLE #Interval2
(
RunID INT IDENTITY(10001,1) NOT NULL PRIMARY KEY,
_Time INT NOT NULL,
NextRunTime DATETIME NOT NULL
)
GO

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

INSERT INTO #Interval2 (_TIME,NextRunTime) SELECT SUBSTRING(_Time,7,1),NextRunTime FROM #Interval WHERE LEFT(_Time,5) = 'Every'
GO

CREATE TABLE #Runstart
(
StartID INT IDENTITY(10001,1) NOT NULL PRIMARY KEY,
RunID INT NOT NULL,
[Start_DTTM] DATETIME
)
GO

Затем заполните таблицу #RUNSTART, используя этот цикл:

DECLARE @RunID INT = 10001
DECLARE @RunTime INT = (SELECT _TIME FROM #Interval2 WHERE RunID = @RunID)
DECLARE @NextRun DATETIME = (SELECT NextRunTime FROM #Interval2 WHERE RunID = @RunID)

WHILE @RunID <= (SELECT MAX(RunID) FROM #Interval2)

BEGIN

WHILE @NextRun < (SELECT DATEADD(DD,1,NextRunTime) FROM #Interval2 WHERE RunID = @RunID)

BEGIN

INSERT INTO #Runstart (RunID,[Start_DTTM]) SELECT @RunID,DATEADD(HH,@RunTime,@NextRun)

SET @NextRun = (SELECT DATEADD(HH,@RunTime,@NextRun))

END

SET @RunID = @RunID+1
SET @RunTime = (SELECT _TIME FROM #Interval2 WHERE RunID = @RunID)
SET @NextRun = (SELECT NextRunTime FROM #Interval2 WHERE RunID = @RunID)

END
GO

SELECT StartID, RunID,CONVERT(VARCHAR,START_DTTM,108) AS Start_time FROM #RUNSTART
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...