根据前面的行查询行

Query rows based on previous rows

我有一个 table,里面有一些金融价格数据。此数据具有类型('T'、'B' 或 'S' 之一)、时间戳和价格。我需要找到 'T' 类型的行,其价格低于前一个 'B' 类型行的价格或高于前一个 'S' 类型行的价格。

这是一些示例数据:

+-------+------+----------------------------------+---------------+
| id    | type | htime                            | price         |
+-------+------+----------------------------------+---------------+
|  4505 | T    | 2022-04-24 19:41:00.585891       | 5799.30000000 |
|  4506 | B    | 2022-04-24 19:41:00.585891       | 5799.00000000 |
|  4507 | S    | 2022-04-24 19:41:00.586754       | 5801.40000000 |
|  4508 | S    | 2022-04-24 19:41:00.586802       | 5801.10000000 |
|  4509 | B    | 2022-04-24 19:41:00.586818       | 5799.30000000 |
|  4510 | T    | 2022-04-24 19:41:00.586820       | 5799.30000000 |
|  4511 | T    | 2022-04-24 19:41:00.586820       | 5799.00000000 |
|  4512 | B    | 2022-04-24 19:41:00.586820       | 5799.00000000 |
|  4515 | S    | 2022-04-24 19:41:00.587087       | 5801.10000000 |
|  4516 | S    | 2022-04-24 19:41:00.588252       | 5801.10000000 |
|  4591 | S    | 2022-04-24 19:41:00.639867       | 5801.10000000 |
|  4608 | T    | 2022-04-24 19:41:00.657640       | 5798.00000000 |
|  4609 | B    | 2022-04-24 19:41:00.657640       | 5797.20000000 |
+-------+------+----------------------------------+---------------+

所以在这里我想查询 ID 为 4511 的 return 行(类型 = 'T' 并且价格低于类型 = 'B' 的前一行的价格)和 4608(同样的原因)。我不要第4510行,因为它的价格既不低于前'B'行也不高于前'S'行。我可能只想忽略第 4505 行,但那里发生的事情对我来说并不重要。

我试过以下查询:

WITH bids AS (SELECT * FROM my_table WHERE type = 'B'),
     offers AS (SELECT * FROM my_table WHERE type = 'S')
SELECT *
FROM (SELECT * FROM my_table WHERE type = 'T') trades
WHERE trades.price < (SELECT price FROM bids WHERE bids.htime < trades.htime ORDER BY htime DESC LIMIT 1)
   OR trades.price > (SELECT price FROM offers WHERE offers.htime < trades.htime ORDER BY htime DESC LIMIT 1);

但是速度非常慢。我希望有一个更简单的自连接类型解决方案,但我对此很陌生。

table 在 (type, htime) 上有一个索引。

我正在使用 MariaDB 10.5.13

您好,欢迎来到 SO!

试试这个查询,理论上应该不会慢。

这个解决方案的想法是在 select 子句中添加一个额外的结果,该结果将使用子查询生成,如果不满足条件,则结果将为 null 或 id符合条件的前一行。

最后,您可以将其包装到一个额外的 select 中,以显示实际符合条件的行。

select results.id, results.previousId from (
    select t1.*, (select t2.id from test22 t2 
    where t1.type = 'T' 
    and ((t2.type='B' and t1.price<t2.price) or (t2.type='S' and t1.price>t2.price)) 
    and t2.htime<t1.htime order by t2.htime asc limit 1) as previousId
    from test22 as t1) 
as results 
where results.previousId is not null;