2013-05-13 3 views
8

У меня есть таблица с первичным ключом (bigint), datetime, value, foreignKey, который содержит 100 000 строк. Я хочу иметь возможность получить строку для переменного временного интервала. Например.Выбирать строки на основе каждого n-го интервала времени

Select Timestamp, value from myTable where configID=3 
    AND{most recent for 15 min interval} 

У меня есть запрос КТР, который возвращает несколько строк для интервала интервала

WITH Time_Interval(timestamp, value, minutes) 
    AS 
    (
     Select timestamp, value, DatePart(Minute, Timestamp) from myTable 
     Where Timestamp >= '12/01/2012' and Timestamp <= 'Jan 10, 2013' and 
     ConfigID = 435 and (DatePart(Minute, Timestamp) % 15) = 0 
    ) 
    Select Timestamp, value, minutes from Time_Interval 
    group by minutes, value, timestamp 
    order by Timestamp 

, такие как:

2012-12-19 18:15:22.040 6.98 15 
    2012-12-19 18:15:29.887 6.98 15 
    2012-12-19 18:15:33.480 7.02 15 
    2012-12-19 18:15:49.370 7.01 15 
    2012-12-19 18:30:41.920 6.95 30 
    2012-12-19 18:30:52.437 6.93 30 
    2012-12-19 19:15:18.467 7.13 15 
    2012-12-19 19:15:34.250 7.11 15 
    2012-12-19 19:15:49.813 7.12 15 

Но, как можно видеть, есть 4 за 1 15 мин интервал, 2 для следующего интервала и т. д. Хуже, Если данные не были получены при точной отметке времени 15 минут, тогда значения не будет.

То, что я хочу, является самым последним значением для пятнадцатиминутного интервала ... если если только данные для этой интервала произошли через 1 секунду после начала интервала.

Я думал о Lead/over, но снова ... строки не упорядочены таким образом. Первичный ключ - это bigInt и представляет собой кластерный индекс. Столбец timstamp и столбцы ConfigID индексируются. Вышеуказанный запрос возвращает 4583 строки за секунду.

Спасибо за любую помощь.

ответ

1

Попробуйте это для размера. Он даже обрабатывает возврат одной строки для экземпляров, когда у вас есть несколько временных меток за данный интервал. ПРИМЕЧАНИЕ. Предполагается, что ваш столбец Bigint PK называется: idx. Просто замените, где вы видите «idx», если это не так.

;WITH Interval_Helper([minute],minute_group) 
    AS 
    (
       SELECT 0, 1 UNION SELECT 1, 1 UNION SELECT 2, 1 UNION SELECT 3, 1 UNION SELECT 4, 1 
     UNION SELECT 5, 1 UNION SELECT 6, 1 UNION SELECT 7, 1 UNION SELECT 8, 1 UNION SELECT 9, 1 
     UNION SELECT 10, 1 UNION SELECT 11, 1 UNION SELECT 12, 1 UNION SELECT 13, 1 UNION SELECT 14, 1 
     UNION SELECT 15, 2 UNION SELECT 16, 2 UNION SELECT 17, 2 UNION SELECT 18, 2 UNION SELECT 19, 2 
     UNION SELECT 20, 2 UNION SELECT 21, 2 UNION SELECT 22, 2 UNION SELECT 23, 2 UNION SELECT 24, 2 
     UNION SELECT 25, 2 UNION SELECT 26, 2 UNION SELECT 27, 2 UNION SELECT 28, 2 UNION SELECT 29, 2 
     UNION SELECT 30, 3 UNION SELECT 31, 3 UNION SELECT 32, 3 UNION SELECT 33, 3 UNION SELECT 34, 3 
     UNION SELECT 35, 3 UNION SELECT 36, 3 UNION SELECT 37, 3 UNION SELECT 38, 3 UNION SELECT 39, 3 
     UNION SELECT 40, 3 UNION SELECT 41, 3 UNION SELECT 42, 3 UNION SELECT 43, 3 UNION SELECT 44, 3 
     UNION SELECT 45, 4 UNION SELECT 46, 4 UNION SELECT 47, 4 UNION SELECT 48, 4 UNION SELECT 49, 4 
     UNION SELECT 50, 4 UNION SELECT 51, 4 UNION SELECT 52, 4 UNION SELECT 53, 4 UNION SELECT 54, 4 
     UNION SELECT 55, 4 UNION SELECT 56, 4 UNION SELECT 57, 4 UNION SELECT 58, 4 UNION SELECT 59, 4 

    ) 
    ,Time_Interval([timestamp], value, [date], [hour], minute_group) 
    AS 
    (
     SELECT A.[Timestamp] 
      ,A.value 
      ,CONVERT(smalldatetime, CONVERT(char(10), A.[Timestamp], 101)) 
      ,DATEPART(HOUR, A.[Timestamp]) 
      ,B.minute_group 
     FROM myTable A 
     JOIN Interval_Helper B 
      ON (DATEPART(minute, A.[Timestamp])) = B.[minute] 
      AND A.[Timestamp] >= '12/01/2012' 
      AND A.[Timestamp] <= '01/10/2013' 
      AND A.ConfigID = 435 
    ) 
    ,Time_Interval_TimeGroup([date], [hour], [minute], MaxTimestamp) 
    AS 
    (
     SELECT [date] 
       ,[hour] 
       ,minute_group 
       ,MAX([Timestamp]) as MaxTimestamp 
      FROM Time_Interval 
     GROUP BY [date] 
       ,[hour] 
       ,minute_group 
    ) 
    ,Time_Interval_TimeGroup_Latest(MaxTimestamp, MaxIdx) 
    AS 
    (
     SELECT MaxTimestamp 
       ,MAX(idx) as MaxIdx 
      FROM myTable A 
      JOIN Time_Interval_TimeGroup B 
      ON A.[Timestamp] = B.MaxTimestamp 
     GROUP BY MaxTimestamp 
    ) 


    SELECT A.* 
     FROM myTable A 
     JOIN Time_Interval_TimeGroup_Latest B 
     ON A.idx = B.MaxIdx 
    ORDER BY A.[timestamp] 

Это еще один взять на себя умную функцию времени группы из @MntManChris ниже:

CREATE FUNCTION dbo.fGetTimeGroup (@DatePart tinyint, @Date datetime) 
RETURNS int 
AS 
BEGIN 
RETURN CASE @DatePart 
      WHEN 1 THEN DATEPART(mi, @Date) 
      WHEN 2 THEN DATEPART(mi, @Date)/5 + 1 -- 5 min 
      WHEN 3 THEN DATEPART(mi, @Date)/15 + 1 -- 15 min 
      WHEN 4 THEN DATEPART(mi, @Date)/30 + 1 -- 30 min 
      WHEN 5 THEN DATEPART(hh, @Date)   -- hr 
      WHEN 6 THEN DATEPART(hh, @Date)/6 + 1 -- 6 hours 
      WHEN 7 THEN DATEPART(hh, @Date)/12 + 1 -- 12 hours 
      WHEN 8 THEN DATEPART(d, @Date)   -- day 
      ELSE -1 
     END 
END 
+0

Это, кажется, ответ, который я искал. Хотя я не уверен, как лучше всего реализовать его, если интервал изменяется от 15 минут до 5 или 1 или даже до 6 часов. Мне придется изучить его еще немного. – MtnManChris

+0

Если вам нужно, чтобы интервал был переменным, затем динамически загружайте Interval_Helper с каждой минутой дня (1440 записей) и динамически настраивайте назначение минуты_группы на основе нужной вам группы интервалов. Вам также потребуется настроить соединение DATEPART на минутном столбце, чтобы также включить умножение компонента HOUR на 60 плюс компонент MINUTE метки времени. –

+0

Rob, То, что я закончил, создало пользовательскую функцию, которая в основном избавилась от соединения с Interval_Helper. Таким образом, строка «, B.minute_group стала« dbo.fGetTimeGroup (@tInterval, A. [Timestamp]) как «time_group». – MtnManChris

1

Если вы хотите разбить за 15 минут, используйте датичный в минутах и ​​делите на 15. И используйте этот раздел для ранжирования каждого интервала.

WITH myTbl AS 
(
SELECT 
timestamp, value, 
RANK() OVER (PARTITION BY (DATEDIFF(Mi,0, Timestamp)/15) ORDER BY Timestamp desc) RK 
FROM myTable 
--WHERE Timestamp BETWEEN '' AND '' 
) 

SELECT * FROM myTble 
WHERE RK <= 1 
+0

Спасибо, хотя мне нравится простота кода, кажется, есть много строк, которые отсутствуют в результате. Приведенный выше код правильно отображает эти строки. – MtnManChris

1

Как мой комментарий выше говорит, что я использовал ответ Робы, но implmented пользовательской функции для устранения таблицу Interval_Helper и первое соединение. Вот код для пользовательской функции.

BEGIN 
DECLARE @Ans integer 
if @DatePart = 1 -- min 
    return DATEPART(mi, @Date) 
if @DatePart = 2 -- 5 min 
    return DatePart(mi,@Date)/5 + 1 
if @DatePart = 3 -- 15 min 
    return DatePart(mi,@Date)/15 + 1 
if @DatePart = 4 -- 30min 
    return DatePart(mi,@Date)/30 + 1 
if @DatePart = 5 -- hr 
    return DATEPART(hh, @Date) 
if @DatePart = 6 -- 6 hours 
    return DATEPART(hh, @Date)/6 + 1 
if @DatePart = 7 -- 12 hours 
    return DATEPART(hh, @Date)/12 + 1 
if @DatePart = 8 -- day 
    return DATEPART(d, @Date) 


return -1 
END 

Это тогда сделал таблицу TIME_INTERVAL выглядеть

;WITH Time_Interval([timestamp], value, [date], [day], time_group) 
AS 
(
    SELECT A.[Timestamp] 
     ,A.value 
     ,CONVERT(smalldatetime, CONVERT(char(10), A.[Timestamp], 101)) 
     ,DATEPART(dd, A.[Timestamp]) 
     ,dbo.fGetTimeGroup(@tInterval, A.[Timestamp]) as 'time_group' 
    FROM myTable A 
     where 
     A.[Timestamp] >= '12/01/2012' 
     AND A.[Timestamp] <= '01/10/2013' 
     AND A.ConfigID= 435 
) 

Поскольку существует переход от «часов» в «дни», как @TimeInterval идет от 1 часа до 6 ч или 12 ч или каждый день , Мне также пришлось переключить таблицу таблицы Time_Interval_TimeGroup с группировки на [час] на группировку на [день] и, конечно, иметь это в списке выбора.

Поскольку это часть гораздо более широкой абстрактной схемы БД, где и рассматриваемая таблица, и db являются функциями ConfigID и, следовательно, требуют динамического SQL, внедрение этого переключателя в группу не было проблемой, я просто вложил два разных разделы dynSql на основе значения @TimeInterval

Благодаря

+0

Хорошая работа! Было предложено избегать инструкций IF в вашей функции и просто объедините всю логику в оператор CASE. Избегайте инструкций IF, когда это возможно, всего лишь один из трюков настройки производительности, которые я узнал на протяжении многих лет с SQL Server. Я отредактировал свой ответ, чтобы включить версию функции, которую я предлагаю. –

Смежные вопросы