views:

174

answers:

3
+2  Q: 

PostGres if query?

Is there a way to select records based using an if statement?

My table looks like this:

id | num | dis 
1  | 4   | 0.5234333
2  | 4   | 8.2234
3  | 8   | 2.3325
4  | 8   | 1.4553
5  | 4   | 3.43324

And I want to select the num and dis where dis is the lowest number... So, a query that will produce the following results:

id | num | dis 
1  | 4   | 0.5234333
4  | 8   | 1.4553
+2  A: 

If you want all the rows with the minimum value within the group:

SELECT id, num, dis
FROM table1 T1
WHERE dis = (SELECT MIN(dis) FROM table1 T2 WHERE T1.num = T2.num)

Or you could use a join to get the same result:

SELECT T1.id, T1.num, T1.dis
FROM table1 T1
JOIN (
    SELECT num, MIN(dis) AS dis
    FROM table1
    GROUP BY num
) T2
ON T1.num = T2.num AND T1.dis = T2.dis

If you only want a single row from each group, even if there are ties then you can use this:

SELECT id, dis, num FROM (
    SELECT id, dis, num, ROW_NUMBER() OVER (PARTITION BY num ORDER BY dis) rn
    FROM table1
) T1
WHERE rn = 1

Unfortunately this won't be very efficient. If you need something more efficient then please see Quassnoi's page on selecting rows with a groupwise maximum for PostgreSQL. Here he suggests several ways to perform this query and explains the performance of each. The summary from the article is as follows:

Unlike MySQL, PostgreSQL implements several clean and documented ways to select the records holding group-wise maximums, including window functions and DISTINCT ON.

However to the lack of the loose index scan support by the PostgreSQL’s optimizer and the less efficient usage of indexes in PostgreSQL, the queries using these function take too long.

To work around these problems and improve the queries against the low cardinality grouping conditions, a certain solution described in the article should be used.

This solution uses recursive CTE’s to emulate loose index scan and is very efficient if the grouping columns have low cardinality.

Mark Byers
+1  A: 

Use this:

SELECT DISTINCT ON (num) id, num, dis
FROM tbl
ORDER BY num, dis

Or if you intend to use other RDBMS in future, use this:

select * from tbl a where dis =
(select min(dis) from tbl b where b.num = a.num)
Michael Buen
A: 

If you need to have IF logic you can use PL/pgSQL.

http://www.postgresql.org/docs/8.4/interactive/plpgsql-control-structures.html

But try to solve your issue with SQL first if possible, it will be faster and use PL/pgSQL when SQL can't solve your problem.

StarShip3000