2009-03-04 11 views
1

私はかなり奇妙な問題に遭遇しました。私はmysqlデータベースで作業するには、次のサンプルデータを持っている:何が起こっているSQL:サブクエリに基づいて結果セットを制限する必要があります

 
    |key| data| index | total | timestamp   | 
    | # | a | 1  | 2  | 2009-01-02 01:01:32 | 
    | $ | b | 2  | 2  | 2009-01-02 01:03:32 | 
    | % | c | 1  | 3  | 2009-01-03 01:01:32 | 
    |^| d | 2  | 3  | 2009-01-03 01:04:32 | 
    | & | e | 3  | 3  | 2009-01-03 01:02:32 | 
    | * | f | 1  | 2  | 2009-01-05 01:01:32 | 

は(ない私の制御下にある)別のプロセスは、データパケットを受信し、タイムスタンプを直接データベースにそれらを格納していることです到着時刻。パケットはバーストに到達するはずです... a、bは互いに近くに到着し、1と2のインデックスが付けられ、各パケットは送信されたパケットの総数を含みます。 keyは通常の自動インクリメントプライマリキーです。

私が必要とするのは、到着した最新のリストを表示するビューです(パケットのすべてが到着していない場合は部分リストが受け入れ可能です)。

上記のクエリの結果は、理想的には "f"にする必要がありますが、私はそれを行う方法は見ていません。私たちが別の方法でそれを得ることができないならば、 "a"と "f"を返すことは受け入れられるでしょう。つまり、select文で捕捉される少量の余分なデータは大きな問題ではありません。 "f"が到着する前の期間、正しい戻り値はc、d、eです。あなたのいくつかは、おそらくあなたは(少なくとも、MySQLで)LIMIT句でサブクエリを行うことができない、気付いてきたように

 
SELECT * FROM table WHERE total = (
    SELECT total FROM table WHERE timestamp = (
     SELECT MAX(timetamp) FROM table 
    ) 
) 
ORDER BY DESC timestamp 
LIMIT (
    SELECT total FROM table WHERE timestamp = (
     SELECT MAX(timetamp) FROM table 
) 

私の一般的な考えはの線に沿っていました。誰もがこの問題を解決する別のアプローチを持っていますか?上記のクエリは、最近のIDの小さなリストにJOINを入れ子にすることで、よりきれいにすることができますが、サブクエリのLIMITサブクエリの問題は残ります。

2段階クエリとして、これは比較的簡単です。問題は、VIEWの定義文を定義する必要があることです。

編集私は示唆しています間違ったSQLの例を修正する

+0

"最新"の構成を明確に説明できますか? "F"と "A"は受け入れられると言っているので、それはまっすぐなタイムスタンプのようには見えません。 –

+0

私は、一意の「インデックス」値を保証し、「合計」行以上を返さないようにする方法を想定していました。基本的には、 "f"が返されることは重要ですが、 "a"を返すことも致命的な欠陥ではないと言っています。 – user73917

+0

コレクションごとに識別子がないことは残念です。コレクションのスパンが2日以上ある場合や2つのコレクションが重複している場合は、問題が発生します。 – Adam

答えて

1

クエリ:

SELECT * 
FROM packets 
WHERE total = (SELECT total 
       FROM packets 
       WHERE timestamp = (SELECT MAX(timestamp) FROM packets)) 
    AND timestamp >= (SELECT MAX(timestamp) FROM packets WHERE idx = 1) 
ORDER BY timestamp DESC; 

不作為:

mysql> create table packets(id bigint(20) AUTO_INCREMENT primary key, data char(1), idx int(10), total int(10), timestamp datetime); 
Query OK, 0 rows affected (0.00 sec) 

mysql> insert into packets(data, idx, total, timestamp) values('a', 1 ,2,'2009-01-02 01:01:32'), 
    ->  ('b' ,2 ,2,'2009-01-02 01:03:32'), 
    ->  ('c' ,1 ,3,'2009-01-03 01:01:32'), 
    ->  ('d' ,2 ,3,'2009-01-03 01:04:32'), 
    ->  ('e' ,3 ,3,'2009-01-03 01:02:32'), 
    ->  ('f' ,1 ,2,'2009-01-05 01:01:32'); 
Query OK, 6 rows affected (0.00 sec) 
Records: 6 Duplicates: 0 Warnings: 0 

mysql> SELECT * 
    -> FROM packets 
    -> WHERE total = (SELECT total 
    -> FROM packets 
    -> WHERE timestamp = (SELECT MAX(timestamp) FROM packets)) 
    -> AND timestamp >= (SELECT MAX(timestamp) FROM packets WHERE idx = 1) 
    -> ORDER BY timestamp DESC; 
+----+------+------+-------+---------------------+ 
| id | data | idx | total | timestamp   | 
+----+------+------+-------+---------------------+ 
| 6 | f | 1 |  2 | 2009-01-05 01:01:32 | 
+----+------+------+-------+---------------------+ 
1 row in set (0.00 sec) 

mysql> delete from packets where id = 6; 
Query OK, 1 row affected (0.00 sec) 

mysql> SELECT * FROM packets WHERE total = (SELECT total FROM packets WHERE timestamp = (SELECT MAX(timestamp) FROM packets)) AND timestamp >= (SELECT MAX(timestamp) FROM packets WHERE idx = 1) ORDER BY timestamp DESC; 
+----+------+------+-------+---------------------+ 
| id | data | idx | total | timestamp   | 
+----+------+------+-------+---------------------+ 
| 4 | d | 2 |  3 | 2009-01-03 01:04:32 | 
| 5 | e | 3 |  3 | 2009-01-03 01:02:32 | 
| 3 | c | 1 |  3 | 2009-01-03 01:01:32 | 
+----+------+------+-------+---------------------+ 
3 rows in set (0.00 sec) 

mysql> 
+0

いいえ...しかし、なぜ質問が混乱していたのか分かります... "f"の到着前の期間、正しい返信はc、d、eです。 – user73917

+0

私はクエリが – sfossen

+0

に更新されたことに注意してください.fの到着前には、dのタイムスタンプだけが一致するため、 "d"を返します。 (パケットが順番に到着しない、または一度に到着しない) – user73917

0

彼らは、以下の、間に書き込まれている他のパケットずに順番に到着した場合うまくいくはずです。

SELECT * 
FROM Total t 
    INNER JOIN (
     SELECT Total, Timestamp 
     FROM Total t 
      INNER JOIN (
       SELECT Timestamp = MAX(Timestamp) 
       FROM Total 
       WHERE ID = 1 
      ) ts ON ts.Timestamp = t.Timestamp. 
    ) tit ON tit.Total = t.Total AND tit.Timestamp <= t.Timestamp 
+0

私はこのようなアプローチになるかもしれません。不幸にも、時にはこれらのタイムスタンプは互いに数時間ずれていることがあります。 不思議なことに、これは非常に間欠的なパイプを使ってリモートセンシングのサイエンスデータです。 – user73917

+0

@kiruwa、そうであれば、最後の送信からすべてのデータを取得するクエリを確実に構築することはできません。同じ合計で2つの送信がパケットの間に数時間の間隔で到着した場合、あなたは運命に陥っています... doomed私は言う

+0

ええ、試みはちょうど近いものを得ることでした。 foo = SELECT総FROMテーブルWHERE timestamp =(SELECT MAX(タイムスタンプ)...) SELECT * FROMテーブルWHERE合計= $ foo ORDER BY DESCタイムスタンプLIMIT foo – user73917

0

これは私がSQLサーバで行う方法です。あなたはmysql構文に変換できます。

SELECT * 
FROM table 
    INNER JOIN (SELECT TOP 1 * FROM table ORDER BY key DESC) AS t ON (table.timestamp = t.timestamp AND table.total = t.total) 
0

私は少し異なるクエリフォームと一緒に行くことになった:

 
CREATE VIEW NewestTimestamps AS 
    SELECT index, MAX(timestamp) AS maxTS FROM table GROUP BY index; 

CREATE VIEW NewestList AS 
    SELECT * FROM table AS t 
    JOIN NewestTimestamps sub ON t.timestamp = sub.maxTS AND sub.index = t.index 
    WHERE t.total = (SELECT t2.total FROM table AS t2 
    WHERE timestamp = (SELECT MAX(timestamp) FROM table) 
); 

このリストには、私が尋ね正確ではありませんが、確実に新旧のデータを区別するために、実際に不可能です。代わりに、これは私にインデックス1の最新の要素を与え、次にインデックス2などを与えます。さらに、WHERE句は、ビューのサイズを直近に到着したキューのサイズに制限します。

mysqlはビューのFROM句でサブクエリを許可しないため、最初のビューが必要であることに注意してください。

関連する問題