如何从mysql表中查找元素的前置和后继?

时间:2016-06-18 18:09:29

标签: mysql sql postgresql

我在mysql数据库中有一个名为student的表,如下所示。

name value
sdf  -3
abc   3   
ddf   4
sdf   7

给定一个值,我应该能够找到最接近它的值,但是一个值较小而另一个值较大。

例如:给定3,输出应为-3和4

我有一个类似的解决方案:

(select value from student where value>3 order by value desc limit 1)
union
(select value from student where value<3 order by value desc limit 1)

但是我想要一个能够有效地遍历表并产生结果的查询。你能帮我找到吗?

2 个答案:

答案 0 :(得分:0)

以下内容应该有效,但确定只扫描

SELECT max(if(value < 3, value, NULL)) AS predecessor,
       min(if(value > 3, value, NULL)) AS successor
FROM TABLE;

根据wikipedia,十万行是~10 ^ 5行。在现代硬件上,你应该没问题。在MacBook Pro上测试:

mysql> SELECT max(if(value < 3, value, NULL)) AS predecessor,        min(if(value > 3, value, NULL)) AS successor FROM toto;
+-------------+-----------+
| predecessor | successor |
+-------------+-----------+
|           2 |         4 |
+-------------+-----------+
1 row in set (0.35 sec)

mysql> select count(*) from toto;
+----------+
| count(*) |
+----------+
|  1000004 |
+----------+
1 row in set (0.23 sec)

答案 1 :(得分:0)

如果您使用的是Postgressql,Oracle或sql-server,那么如果值重复,这应该可以工作并忽略

WITH cte AS (
  SELECT
    *
    ,DENSE_RANK() OVER (ORDER BY value ASC) AS Rank
  FROM
    Tbl
)

SELECT
  c.name
  ,c.value
  ,p.value AS Predesessor
  ,s.value AS Successor
FROM
  cte c
  LEFT JOIN cte s
  ON (c.Rank + 1) = s.Rank
  LEFT JOIN cte p
  ON (c.Rank - 1) = p.Rank