2013-05-11 2 views
5

У меня есть большая таблица с записями, созданная каждую секунду, и вы хотите выбрать только те записи, которые были созданы в верхней части каждого часа за последние 2 месяца. Таким образом, мы получили бы 24 выбранных записей на каждый день в течение последних 60 днейSQL Server - выберите все записи сверху часа

структура

таблица является Dateandtime, Значение1, значение2, и т.д.

Большое спасибо

+4

Покажите нам, что вы попробовали –

+2

Определите "верхний час каждого часа" очень четко - например. '' 2013-05-11 09: 00: 00.000'', но не '' 2013-05-11 09: 00: 01.000'' и т. Д.Уровень точности, который вы намереваетесь, поможет определить, какие временные элементы являются действительными критериями. – J0e3gan

ответ

0

Try:

select * from mytable 
where datepart(mi, dateandtime)=0 and 
     datepart(ss, dateandtime)=0 and 
     datediff(d, dateandtime, getdate()) <=60 
+0

Это кажется опасным, так как предполагает, что все записи записываются каждую секунду без дубликатов в течение данной секунды. –

+0

@GordonLinoff: В самом деле - это моя интерпретация *, с записями, созданными каждую секунду * * части вопроса. –

+0

Спасибо, хорошо работал, поскольку дубликатов не было – user2119912

2

Вы могли group by на части даты (cast(col1 as date)) . и час часть (datepart(hh, col1) Затем выберите минимальную дату в течение каждого часа, и фильтр на что:

select * 
from YourTable yt 
join (
     select min(dateandtime) as dt 
     from YourTable 
     where datediff(day, dateandtime, getdate()) <= 60 
     group by 
       cast(dateandtime as date) 
     ,  datepart(hh, dateandtime) 
     ) filter 
on  filter.dt = yt.dateandtime 

в качестве альтернативы, можно сгруппировать по формату даты, только включает в себя дату и хоу р. Например, convert(varchar(13), getdate(), 120) возвращает 2013-05-11 18.

 ... 
     group by 
       convert(varchar(13), getdate(), 120) 
     ) filter 
     ... 
1

Вы можете использовать оконные функции для этого:

select dateandtime, val1, val2, . . . 
from (select t.*, 
      row_number() over (partition by cast(dateandtime as date), hour(dateandtime) 
           order by dateandtime 
           ) as seqnum 
     from t 
    ) t 
where seqnum = 1 

Функция row_number() присваивает порядковый номер каждой группы, определенной пунктом partition - в этом случае каждый час каждого дня. Внутри этой группы он заказывает значение dateandtime, поэтому ближайший к вершине часа получает значение 1. Внешний запрос просто выбирает эту одну запись для каждой группы.

Возможно, вам понадобится дополнительная статья фильтра, чтобы получить записи за последние 60 дней. Используйте это в подзапрос:

where dateandtime >= getdate() - 60 
2

Для ясности, я бы, вероятно, использовать два этапа, КТР на основе подхода (это работает в SQL Server и новее - вы не четко указать, какие версии в SQL Server, который вы используете, так что я просто надеюсь, что ты не на древней версии как 2000 больше):

-- define a "base" CTE to get the hour component of your "DateAndTime" 
-- column and make it accessible under its own name 
;WITH BaseCTE AS 
(
    SELECT 
     ID, DateAndTime, 
     Value1, Value2, 
     HourPart = DATEPART(HOUR, DateAndTime) 
    FROM dbo.YourTable 
    WHERE DateAndTime >= @SomeThresholdDateHere 
), 
-- define a second CTE which "partitions" the data by this "HourPart", 
-- and number all rows for each partition starting at 1. So each "last" 
-- event for each hour is the one with the RN = 1 value 
HourlyCTE AS 
(
    SELECT ID, DateAndTime, Value1, Value2, 
     RN = ROW_NUMBER() OVER(PARTITION BY HourPart ORDER BY DateAndTime DESC) 
    FROM BaseCTE 
) 
SELECT * 
FROM HourlyCTE 
WHERE RN=1 

Также: я не был уверен, что именно точно Вы имеете в виду под «вершиной часа» - строкой, которая была создана в начале каждого часа (например, на 04:00:00) - вернее, последний ряд, созданный в промежуток времени этого часа? Если вы имеете в виду первый за каждый час - то вам нужно изменить ORDER BY DateAndTime DESC к ORDER BY DateAndTime ASC

2

Вы можете использовать опцию с EXISTS оператор

SELECT * 
FROM dbo.tableName t 
WHERE t.DateAndTime >= @YourDateCondition 
    AND EXISTS (
       SELECT 1 
       FROM dbo.tableName t2 
       WHERE t2.Dateandtime >= DATEADD(HOUR, DATEDIFF(HOUR, 0, t.Dateandtime), 0) 
         AND t2.Dateandtime < DATEADD(HOUR, DATEDIFF(HOUR, 0, t.Dateandtime)+1, 0) 
       HAVING MAX(t2.Dateandtime) = t.Dateandtime 
      ) 

или вариант с CROSS APPLY оператора

SELECT * 
FROM dbo.test83 t CROSS APPLY (
           SELECT 1 
           FROM dbo.test83 t2 
           WHERE t2.Dateandtime >= DATEADD(HOUR, DATEDIFF(HOUR, 0, t.Dateandtime), 0) 
            AND t2.Dateandtime < DATEADD(HOUR, DATEDIFF(HOUR, 0, t.Dateandtime)+1, 0) 
           HAVING MAX(t2.Dateandtime) = t.Dateandtime        
           ) o(IsMatch) 
WHERE t.DateAndTime >= @YourDateCondition 

Для улучшения показателей эффективности используют этот индекс:

CREATE INDEX x ON dbo.test83(DateAndTime) INCLUDE(Value1, Value2) 
Смежные вопросы