1

我遇到了一个相当奇怪的问题。我有以下示例数据可以在 mysql 数据库中使用:

    |钥匙| 数据| 索引 | 总计| 时间戳 |
    | # | 一个 | 1 | 2 | 2009-01-02 01:01:32 |
    | $ | 乙 | 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 |
    | & | 电子| 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。

我的一般想法是这样的:

SELECT * FROM 表 WHERE 总计 = (
    SELECT total FROM table WHERE timestamp = (
        从表中选择 MAX(时间戳)
    )
)
ORDER BY DESC 时间戳
限制 (
    SELECT total FROM table WHERE timestamp = (
        从表中选择 MAX(时间戳)
)

正如你们中的一些人可能已经注意到的那样,您不能在 LIMIT 子句中执行子查询(至少对于 mysql)。有没有人有另一种方法来解决这个问题?通过将 JOIN 嵌套到最近 id 的小列表中,可以使上面的查询更加清晰,但这仍然会在子查询中留下 LIMIT 子查询问题。

作为一个两阶段查询,这是相对微不足道的。问题是它需要成为 VIEW 的定义选择语句。

编辑以修复错误的 sql 示例

4

4 回答 4

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>
于 2009-03-04T21:13:44.763 回答
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
于 2009-03-04T21:15:54.990 回答
0

这就是我在 sql server 中的做法,您可以转换为 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)
于 2009-03-04T21:21:25.290 回答
0

我最终使用了一个稍微不同的查询表单:

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

创建视图最新列表为
  SELECT * FROM 表 AS t
    加入 NewestTimestamps sub ON t.timestamp = sub.maxTS AND sub.index = t.index
  WHERE t.total = (SELECT t2.total FROM table AS t2
    WHERE 时间戳 = (SELECT MAX(timestamp) FROM table)
  );

这个列表并不是我所要求的,但实际上似乎不可能可靠地区分新旧数据。相反,这将为我提供索引 1 处的最新元素,然后是索引 2,等等……此外,WHERE 子句会将视图的大小限制为最近到达的队列的大小。

请注意,第一个视图是必需的,因为 mysql 不允许视图中的 FROM 子句中的子查询。

于 2009-03-17T18:50:46.243 回答