2009-02-02 1 views
4

내가 해결하려고하는 문제는 내가 다음과 같은 테이블을 가지고 있다는 것입니다.SQL - min()은 가장 낮은 값을 얻고 max()는 가장 높은 값을 얻습니다. 2 번째 (또는 5 번째 또는 n 번째) 최저값을 원하면 어떻게해야합니까?

a 및 b는 다른 테이블의 점을 참조하십시오. distance는 점 사이의 거리입니다.

| 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를 유지하고 싶었다면, 나는 이런 식으로 뭔가를 할 수 :

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

내가 각각 하나의 행이 필요 예 :

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; 

나에게이 같은 결과 테이블을 줄 것이다 값은 a_id이며, 해당 행은 각 a_id에 대해 가장 낮은 거리 값을 가져야합니다.

그러나 각 a_gid에 대해 10 개의 가장 가까운 점을 유지하려고합니다. plpgsql 함수를 사용하여이 작업을 수행 할 수 있지만 더 많은 SQL-y 방법이 있으면 궁금합니다.

min() 및 max()가 nth()와 같은 집계 함수가있는 경우 가장 작은 값과 가장 작은 값을 반환합니다. 위와 비슷한 방식으로이 작업을 수행 할 수 있습니다.

저는 PostgeSQL을 사용하고 있습니다.

답변

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 

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; 
+0

Postgres에는이 Functon이 없지만 올바른 길을 가고 있습니다. 제안이 도움이되어 답을 찾을 수 있습니다. – Rory

+0

이제 PostgreSQL 9.1에는 Window Functions 내에 rank() 함수가 있습니다. http://www.postgresql.org/docs/9.1/static/tutorial-window.html – Stefan

4

저는 포스트그레스를 좋아해서이 질문을 두 번째로 보았습니다.

그래서, 테이블 : 값으로

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 ... 등등.

이 값을 하위 쿼리에 추가하여 필요한 값을 검색 할 수 있습니다. 그래서, 우리가 수행하여 상위 10 가장 낮은 거리와 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 
+0

Dang, 내가 제공 한 데이터 세트에서 예제를 제공 했어야합니다. – Elijah

+0

a_id의 각 값에 대해 가장 낮은 값을 원하므로 작동하지 않습니다. – Rory

+0

DESC (내림차순)를 제거하면 가장 낮은 값 목록이 표시됩니다. SELECT value FROM foo ORDER BY value LIMIT 1 OFFSET 1; 어쨌든, 더 간단한 데이터 세트로 교장을 증명하는 것이 나의 희망이었습니다. – Elijah

0

PostgreSQL의 8.3에 검사 이 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 값이 자체보다 낮은 값을 찾으십시오.

관련 문제