毎秒作成されるレコードを含む大きなテーブルがあり、過去 2 か月間、毎正時に作成されたレコードのみを選択したいと考えています。したがって、過去 60 日間、毎日 24 の選択されたレコードを取得します。
テーブル構造は、Dateandtime、Value1、Value2 などです。
どうもありがとう
毎秒作成されるレコードを含む大きなテーブルがあり、過去 2 か月間、毎正時に作成されたレコードのみを選択したいと考えています。したがって、過去 60 日間、毎日 24 の選択されたレコードを取得します。
テーブル構造は、Dateandtime、Value1、Value2 などです。
どうもありがとう
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
...
わかりやすくするために、おそらく2段階のCTEベースのアプローチを使用します(これはSQL Server 2005以降で機能します-使用している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
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
)
OR オプションと 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)
これにはウィンドウ関数を使用できます。
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 の値を取得します。外側のクエリは、グループごとにこの 1 つのレコードを選択するだけです。
過去 60 日間のレコードを取得するには、追加のフィルター句が必要になる場合があります。サブクエリでこれを使用します。
where dateandtime >= getdate() - 60
試す:
select * from mytable
where datepart(mi, dateandtime)=0 and
datepart(ss, dateandtime)=0 and
datediff(d, dateandtime, getdate()) <=60