SQL - min () получает самое низкое значение, max () - самое высокое, что если я захочу 2-е (или 5-е или n-е) низшее значение? - PullRequest
4 голосов
/ 02 февраля 2009

Проблема, которую я пытаюсь решить, состоит в том, что у меня есть такая таблица:

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. Если бы я хотел сохранить шкаф b для каждого a, я мог бы сделать что-то вроде этого:

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.

Однако я хочу сохранить 10 ближайших пунктов для каждого a_gid. Я мог бы сделать это с помощью функции plpgsql, но мне любопытно, если есть более SQL-у способ.

min () и max () возвращают наименьшее и наибольшее, если бы существовала агрегатная функция, такая как nth (), которая бы возвращала n-е наибольшее / наименьшее значение, тогда я мог бы сделать это аналогично приведенному выше. 1016 *

Я использую PostgeSQL.

Ответы [ 4 ]

4 голосов
/ 02 февраля 2009

Я люблю 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
4 голосов
/ 02 февраля 2009

Попробуйте это:

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

0 голосов
/ 05 февраля 2014

Этот SQL должен найти вам N-ую самую низкую зарплату, которая должна работать в SQL Server, MySQL, DB2, Oracle, Teradata и почти в любой другой СУБД: (примечание: низкая производительность из-за подзапроса)

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 ниже, чем оно само.

0 голосов
/ 02 февраля 2009

Есть ли в 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...