SQL: необходимо ограничить набор результатов на основе подзапроса - PullRequest
1 голос
/ 05 марта 2009

Я столкнулся с довольно странной проблемой. У меня есть следующие примеры данных для работы в базе данных MySQL:

    |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

Ответы [ 4 ]

1 голос
/ 05 марта 2009

запрос, который я предлагаю:

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 голосов
/ 17 марта 2009

Я закончил с немного другой формой запроса:

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 в представлении.

0 голосов
/ 05 марта 2009

Вот как я это сделаю на сервере 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 голосов
/ 05 марта 2009

Если они поступают по порядку, а другие пакеты не записываются между ними, следующее также должно работать.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...