2

私の奇妙な状況を説明するために最善を尽くします。10 分の 1 秒単位で記録された大量のデータがあります。イベントは、時間 X からほぼ毎秒発生します。毎秒は「イベント ウィンドウ」と見なされます。ログに記録された時間は、X からの経過時間です。最初のレコードを「シード」として使用すると、X から 1 秒ごとのウィンドウに記録された最初のレコードのみを返す必要があります。X+1、X+2、X+3 、X+4 など

targets
--------------------------
| id  | time  | name     |
|-----|------ |-----------
| 1   |  1.0  | target01 |
| 2   |  1.1  | target01 |
| 3   |  1.2  | target01 |
| 4   |  1.3  | target01 |
| 5   |  1.4  | target01 |
| 6   |  1.5  | target01 |
| 7   |  1.6  | target01 |
| 8   |  1.7  | target01 |
| 9   |  1.8  | target01 |
| 10  |  1.9  | target01 |
| 11  |  2.0  | target01 |
| 12  |  2.1  | target01 |
| 13  |  2.2  | target01 |

...

| 50  |  4.9  | target01 |
| 51  |  5.3  | target01 |
| 52  |  5.4  | target01 |
| 53  |  5.5  | target01 |
| 54  |  5.6  | target01 |
| 55  |  5.7  | target01 |
| 56  |  5.8  | target01 |
| 57  |  5.9  | target01 |
| 58  |  6.0  | target01 |
| 59  |  6.1  | target01 |
| 60  |  6.2  | target01 |
| 61  |  6.3  | target01 |
| 62  |  6.4  | target01 |
--------------------------

見返りにこれを取得するにはどうすればよいですか:

--------------------------
| id  | time  | name     |
|-----|------ |-----------
| 1   |  1.0  | target01 |
| 11  |  2.0  | target01 |
| 21  |  3.0  | target01 |
| 31  |  4.0  | target01 |
| 51  |  5.3  | target01 |
| 58  |  6.0  | target01 |
--------------------------

レコード 51 が 5.3 秒であることに注意してください。その 4 秒のウィンドウ (X+4) 内に収まる最初のレコードです。

恐ろしいデータベース計画ですが、混乱を継承するのに行き詰まっています。考え?

4

5 に答える 5

0

これを試して:

select *
from targets t
where time % 1 = (
  select min(time % 1) 
  from targets 
  where floor(time) = floor(t.time))

SQLフィドル

于 2012-12-19T20:09:46.073 に答える
0

Rank()のような分析関数が必要ですが、MySQL ではそれができないと確信しています。

select Id, Time, Name
from
(
    SELECT Id, Time, Name, 
           Rank() OVER(PARTITION BY Floor(time) ORDER BY time Asc) AS Rank
    FROM  @aTable
) SubSelect
where Rank = 1

data.stackexchange.com で例を見ることができます。

于 2012-12-19T20:26:05.313 に答える
0

これを行う:

select * from (
    select * from targets
    order by time) x
group by floor(time)

これがSQLFiddleで動作していることを確認してください

于 2012-12-19T18:58:04.880 に答える
0

FLOORおそらくandCOALESCE関数を使用する必要があります

SELECT FLOOR(time) AS whole_second, COALESECE(id), COALESCE(time), COALESCE(name)
FROM table
GROUP BY whole_second
ORDER BY whole_second ASC
于 2012-12-19T18:58:52.823 に答える
0

timeが数値であり、 に「重複する」値がない場合time、次のようなものが機能します。

SELECT d.id
     , d.time
     , d.name
  FROM mytable d
  JOIN ( SELECT MIN(t.time) AS `time`
           FROM mytable t
          GROUP BY FLOOR(t.time)
       ) m
    ON m.time = d.time
 ORDER BY d.time

time(そのクエリでは、1 秒間の最低値に「重複」値がある場合、それらの行の両方が返されます。これは、どちらGROUP BYが任意である限り、最も外側のクエリで単純に対処できます。行が返されます。

(そのクエリは、指定した結果セットを返します。この「名前による」ものも必要かどうかは明確ではないため、省略しました。


他にもいくつかのアプローチがあり、そのうちのいくつかは大規模なセットではるかに優れたパフォーマンスを発揮することに注意してください。


もう 1 つの (MySQL 固有の) アプローチでは、ユーザー変数を使用します。

SELECT t.id
     , t.time
     , t.name
  FROM ( SELECT s.id
              , s.time
              , s.name
              , @prev AS `prev_sec`
              , @prev := FLOOR(s.time) AS `this_sec`
           FROM targets s
           JOIN (SELECT @prev := '') p
          ORDER BY s.time
       ) t
 WHERE prev_sec <> this_sec

(SQL ステートメントのユーザー変数には注意してください。動作が予測可能なステートメントを作成することは可能ですが、実行計画、ステップが実行される順序、および変数が設定されるステップ。


もう 1 つの (通常はパフォーマンスが遅い) 代替手段は、NOT EXISTS述語を使用して、同じ秒内に「早い」時刻がある行を除外することです。

このようなアプローチは、クエリが時間値の小さなセット (つまり、1 年分のデータから 1 時間分の行など、狭い範囲の行) を取得し、適切なインデックス、特にカバリング インデックス、または少なくともtime先行列としてのインデックスが利用可能です。

SELECT t.id
     , t.time
     , t.name
  FROM targets t
 WHERE NOT EXISTS
       ( SELECT 1
           FROM targets e
          WHERE e.time >= FLOOR(t.time)
            AND e.time < t.time
       )
 ORDER
    BY t.time

time(このクエリは、回答で指定された最初のクエリと同様に、それらの値が任意の秒で最も低い場合、重複する値を持つ 2 つ以上の行も返しtimeます。)

于 2012-12-19T19:03:00.843 に答える