【问题标题】:SQL: Need to limit the resultset based on a subquerySQL:需要根据子查询限制结果集
【发布时间】:2010-10-11 09:02:45
【问题描述】:

我遇到了一个相当奇怪的问题。我有以下示例数据可以在 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 示例

【问题讨论】:

  • 你能试着清楚地解释什么是“最近的”吗?既然你说“F”和“A”是可以接受的,它看起来不像是直接的时间戳。
  • 我假设一种方法可以保证唯一的“索引”值,确保返回的行数不超过“总数”行。基本上说虽然返回“f”很关键,但返回“a”也不会是致命缺陷。
  • 很遗憾,每个集合都没有标识符,如果您的集合跨越 2 天,或者两个集合重叠,您将遇到麻烦。
  • 由于索引是按顺序分配的,您可以使用我在下面做的答案。
  • ...或者我在下面做的那个,任何一个都应该工作。

标签: sql mysql subquery


【解决方案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>

【讨论】:

  • 不...但我知道为什么这个问题令人困惑...编辑添加“在“f”到达之前的一段时间内,正确的返回是 c、d 和 e 。”
  • 请注意,在 f 到达之前,它只会返回“d”,因为只有 d 的时间戳会匹配。 (数据包不是按顺序到达,也不是一次全部到达)
  • ok.. 所以我在想,如果它们按顺序到达,请获取最高索引 1,因为您是准时的下限和数据包序列的总数。
【解决方案2】:

这就是我在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)

【讨论】:

    【解决方案3】:

    如果它们按顺序到达而没有在其间写入其他数据包,则以下也应该起作用。

    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
    

    【讨论】:

    • 我最终可能会采用这样的方法。不幸的是,有时这些时间戳可能会相差几个小时。对于好奇的人,这是使用非常间歇性管道的遥感科学数据。
    • @kiruwa,如果是这种情况,您将无法可靠地构造查询以获取上次传输的所有数据。如果两个具有相同总数的传输在它的数据包之间有几个小时的间隔到达,你注定要失败……我说
    • 是的,尝试只是为了接近一些东西。相当于两阶段查询: foo = SELECT total FROM table WHERE timestamp = (SELECT MAX(timestamp)...) SELECT * FROM table WHERE total=$foo ORDER BY DESC timestamp LIMIT foo
    【解决方案4】:

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

    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 子句中的子查询。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-29
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 2016-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多