Возвращает значение столбца на основе столбца даты, принимающего значение, ближайшее к xx:00 и xx:30

#sql #sql-server #sql-server-2016

#sql #sql-сервер #sql-server-2016

Вопрос:

Я пытаюсь возвращать данные с интервалом в 30 минут, но если через 30 минут данных нет, я хотел бы взять значение, ближайшее к отметке 30 минут или 0 минут, с допуском -5 5, если по-прежнему нет данных с этим диапазоном 5 -5, который равен 55-05 или 25-35, будетзначение не возвращается. В настоящее время у меня есть оператор sql, который может возвращать средние значения от 55-05 и 25-35 с интервалом в 30 минут, но мне нужно только 1 значение, которое ближе всего к 30 минутам, я был бы в порядке с 55-00 или 25-30, если 55-05 и 25-35 невозможно выполнить.Инструкция sql, которую я имею сейчас, такова

 SELECT  [target],AVG([Temperature]) as Temperature,AVG([Humidity]) As Humidity,DATEADD(minute,(datediff(minute,0,[Date Time])/30)*30,0) as [Date Time],COUNT (*)                                    
FROM mytable                                    
WHERE DATEPART(minute, [Date Time]) IN (0,1,2,3,4,5,25,26,27,28,29,30,31,32,33,34,35,55,56,57,58,59)                                    
AND (CAST([Date Time] AS DATE)= '2020-09-17')                                   
AND ([target] = '1')                                    
                                    
GROUP BY [target],DATEADD(minute,(datediff(minute,0,[Date Time])/30)*30,0) ORDER BY [Date Time] ASC
output is
Target  Temperature Humidity    Date Time              (No column name)
1       21.100000   76.900000   2020-09-17 00:00:00.000      2
1       21.200000   77.300000   2020-09-17 01:00:00.000      1
1       21.133333   77.333333   2020-09-17 01:30:00.000      3
1       21.100000   77.400000   2020-09-17 02:00:00.000      1
1       21.100000   77.550000   2020-09-17 02:30:00.000      2
1       21.120000   77.640000   2020-09-17 03:00:00.000      5                      
  

Ожидаемый результат должен быть примерно одинаковым, при этом имя столбца не должно быть равно 1, поскольку должно быть возвращено только 1 значение, единственными изменениями будут температура и влажность, не являющиеся средними для диапазона времени 25-35 и 55-05, поэтому полученные данные о температуре и влажности должны быть 1, ближайшими к отметке 30 минут и 0 минут

Ответ №1:

Вы можете использовать ROW_NUMBER() . Но ключевая идея заключается в округлении значений времени до соответствующей «временной группы». Затем вы можете использовать разницу между временем временной группы и временем наблюдаемой даты для упорядочения строк:

 SELECT  t.*                                
FROM (SELECT t.*,
             ROW_NUMBER() OVER (PARTITION BY t.target, v.timegrp
                                ORDER BY ABS(DATEDIFF(SECOND, t.[Date Time], v.timegrp))
                               ) as seqnum
      FROM mytable t CROSS APPLY
           (VALUES (DATEADD(MINUTE,
                            (DATEDIFF(MINUTE, 0, DATEADD(MINUTE, 5, t.[Date Time])) / 30) * 30,
                            0)
                   )
           ) v(timegrp)
      WHERE CAST([Date Time] AS DATE) = '2020-09-17' AND                        
            [target] = '1' AND
            v.timegrp > DATEADD(MINUTE, -5, t.[Date Time]) AND
            v.timegrp < DATEADD(MINUTE, 5, t.[Date Time])
     ) t                                  
WHERE seqnum = 1;
  

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

Комментарии:

1. Большое спасибо за ответ, ваш запрос работает довольно хорошо, за исключением того, возможно ли это, если время даты находится в интервалах 30, 00.00 00.30 и есть значение 2020-09-15 23:57: 22.293 и 2020-09-15 00: 01:17.233, можете ли вы сделать так, чтобы 1 из них равнялся 00.00 (последнее значение)?1, ближайший к 00.00) кроме этого, ответ, который вы дали, довольно хорош

2. @Tim . . . 2020-09-15 не является частью запроса. В противном случае время следует округлить до ближайшего получаса.

3. хммм, я не совсем уверен, что вы подразумеваете под «не частью запроса». я использую этот запрос для отображения диаграмм, для этого вопроса я просто указываю дату в качестве примера, если это не будет (ПРИВЕДЕНИЕ ([Дата Время] КАК ДАТА) = ‘» TxtDate . Текст «‘)