SQL - min()得到最低值,max()得到最高值,如果我想要第二个(或第5个或第n个)最低值怎么办?

时间:2009-02-02 10:37:40

标签: sql postgresql

我试图解决的问题是我有一个这样的表:

a和b指的是另一张桌子上的点。距离是点之间的距离。

| id | a_id | b_id | distance | delete |
| 1  |  1   |   1  |  1       |   0    |
| 2  |  1   |   2  |  0.2345  |   0    |
| 3  |  1   |   3  |  100     |   0    |
| 4  |  2   |   1  |  1343.2  |   0    |
| 5  |  2   |   2  |  0.45    |   0    |
| 6  |  2   |   3  |  110     |   0    |
....

我正在寻找的重要专栏是a_id。如果我想保留每个a的壁橱b,我可以这样做:

update mytable set delete = 1 from (select a_id, min(distance) as dist from table group by a_id) as x where a_gid = a_gid and distance > dist;
delete from mytable where delete = 1;

这会给我一个像这样的结果表:

| id | a_id | b_id | distance | delete |
| 1  |  1   |   1  |  1       |   0    |
| 5  |  2   |   2  |  0.45    |   0    |
....

即。对于a_id的每个值,我需要一行,并且该行应该具有每个a_id的最小距离值。

但是我想为每个a_gid保留10个最接近的点。我可以使用plpgsql函数执行此操作,但我很好奇是否有更多的SQL-y方式。

min()和max()返回最小和最大,如果有一个像nth()这样的聚合函数,它会返回第n个最大/最小值,那么我可以用与上面类似的方式做到这一点。 / p>

我正在使用PostgeSQL。

4 个答案:

答案 0 :(得分:4)

我喜欢postgres,所以我在第二次看到这个问题时把它作为挑战。

所以,对于表:

    Table "pg_temp_29.foo"
 Column |  Type   | Modifiers 
--------+---------+-----------
 value  | integer | 

使用值:

 SELECT value FROM foo ORDER BY value;
 value 
-------
     0
     1
     2
     3
     4
     5
     6
     7
     8
     9
    14
    20
    32
(13 rows)

你可以做:

SELECT value FROM foo ORDER BY value DESC LIMIT 1 OFFSET X

其中X = 0表示最高值,1表示第二高,2 ......等等。

这可以进一步嵌入子查询中以检索所需的值。因此,要使用原始问题中提供的数据集,我们可以通过以下方式获得前十个最低距离的a_ids:

SELECT a_id, distance FROM mytable
 WHERE id IN
  (SELECT id FROM mytable WHERE t1.a_id = t2.a_id
   ORDER BY distance LIMIT 10);
 ORDER BY a_id, distance;

 a_id | distance 
------+----------
    1 |   0.2345
    1 |        1
    1 |      100
    2 |     0.45
    2 |      110
    2 |   1342.2

答案 1 :(得分:4)

试试这个:

SELECT  *
FROM    (
    SELECT  a_id, (
        SELECT b_id
        FROM mytable mib
        WHERE mib.a_id = ma.a_id
        ORDER BY
            dist DESC
        LIMIT 1 OFFSET s
        ) AS b_id
    FROM    (
        SELECT DISTINCT a_id
        FROM mytable mia
        ) ma, generate_series (1, 10) s
    ) ab
WHERE   b_id IS NOT NULL

检查PostgreSQL 8.3

答案 2 :(得分:0)

PostgreSQL是否具有分析函数rank()?如果是这样,试试:

select a_id, b_id, distance
from
( select a_id, b_id, distance, rank() over (partition by a_id order by distance) rnk
  from mytable
) where rnk <= 10;

答案 3 :(得分:0)

这个SQL应该找到你应该在SQL Server,MySQL,DB2,Oracle,Teradata和几乎任何其他RDBMS中工作的第N个最低工资:(注意:由于子查询而性能低下)

SELECT * /*This is the outer query part */
FROM mytable tbl1
WHERE (N-1) = ( /* Subquery starts here */
SELECT COUNT(DISTINCT(tbl2.distance))
FROM mytable tbl2
WHERE tbl2.distance < tbl1.distance)

在上面的查询中要理解的最重要的事情是,每次外部查询处理行时,都会对子查询进行求值。换句话说,内部查询不能独立于外部查询进行处理,因为内部查询也使用tbl1值。

为了找到第N个最低值,我们只找到恰好N-1值低于其自身的值。