2009-03-04 2 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, причем каждый пакет содержит «общее» количество переданных пакетов. ключ - это обычный первичный ключ с автоматическим добавлением.

Что мне нужно - это представление, в котором будет отображаться самый последний список, который прибыл (неполный список, если не все поступившие пакеты, является приемлемым).

Для этого запроса в идеале должен быть только «f», но я не вижу способа сделать это. Если мы не сможем получить его другим способом, то возвращение «a» и «f» будет приемлемым. Другими словами, небольшое количество дополнительных данных, которые вылавливаются оператором select, не является огромной проблемой. В течение периода времени до прибытия «f» правильный возврат - c, d и e.

Мои общие мысли были вдоль линий:

 
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 
) 

Как некоторые из вас, наверное, заметили, вы не можете сделать подзапрос в предложении LIMIT (по крайней мере, с MySQL). У кого-нибудь есть другой подход к решению этой проблемы? Вышеупомянутый запрос можно сделать намного более чистым, вложив JOIN в небольшой список последних идентификаторов, но все еще оставляет проблему подзапроса LIMIT в подзапросе.

В качестве двухэтапного запроса это относительно тривиально. Проблема в том, что он должен стать определяющим оператором select для VIEW.

Редактировать, чтобы исправить неправильный SQL пример

+0

Можете ли вы попытаться четко объяснить, что составляет «последнее»? Поскольку вы говорите, что «F» и «A» будут приемлемы, это не похоже на прямую метку времени. –

+0

Я предполагал подход, в котором вы гарантировали бы уникальные значения «индекса», гарантируя, что вы не вернете больше, чем «полные» строки. В основном говоря, что, хотя для «f» очень важно вернуться, возвращение «а» также не будет фатальным недостатком. – user73917

+0

Жаль, что для каждой коллекции нет идентификатора, если у вас есть диапазон коллекции в течение 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's. (пакеты не поступают ни по порядку, ни сразу) – 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, если это так, вы не можете надежно построить запрос, чтобы получить все данные из последней передачи. Если две передачи с одинаковыми итогами поступают с интервалом в несколько часов между его пакетами, вы обречены ... обречены Я говорю

+0

Да, попытка была просто получить что-то близкое. Эквивалент двухэтапного запроса: foo = SELECT total FROM table WHERE timestamp = (SELECT MAX (временная метка) ...) SELECT * FROM table WHERE total = $ foo ORDER BY DESC timestamp 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 в представлении.