Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL - Conditional aggregation - Avg() in Select statement

I have this table

| user         | Mark       | Points   |
|--------------|------------|----------|
| John         |    0       |    2     |
| Paul         |    5       |    3     |
| John         |    4       |    4     |
| Paul         |    7       |    5     |

I would like to build a query with one select statement that returns the rows shown below. Avg(Mark) - should be average only if Mark>0 Sum(Points) - should be sum of all records.

| user         | Avg(Mark)  | Sum(Points) |
|--------------|------------|-------------|
| John         |    4       |    6        |
| Paul         |    6       |    8        |

Can anyone point to a proper syntax?

I believe it should like :

select user, avg(Mark>0), sum(Points) from Table group by user;
like image 439
Fridolin Avatar asked Jun 20 '13 12:06

Fridolin


People also ask

How do I get AVG in PostgreSQL?

PostgreSQL provides an AVG() function to calculate the average value of a set. The AVG() function is one of the most frequently used aggregate functions in PostgreSQL. The AVG() function enables users to calculate the average value of a numeric column. It can be used with both the SELECT and HAVING clause.

Is AVG () an aggregate function?

AVG() function is an aggregate function that calculates the average value of a numerical dataset that returns from the SELECT statement.

How do you filter aggregate data?

To filter records using the aggregate function, use the HAVING clause. Here we calculate the aggregate value: the average price of each product. One is sold by more than one grocer; therefore the average price is calculated for each (in our example, SELECT name, AVG(price) ).


2 Answers

Starting with version 9.4, PostgreSQL directly supports filtering aggregates.

https://www.postgresql.org/docs/9.4/static/sql-expressions.html

If FILTER is specified, then only the input rows for which the filter_clause evaluates to true are fed to the aggregate function; other rows are discarded.

By using it, your example can be rewritten as:

SELECT
    "user",
    AVG(mark) FILTER (WHERE mark > 0),
    SUM(points)
FROM
    "table"
GROUP BY
    "user"
like image 172
Inego Avatar answered Sep 30 '22 02:09

Inego


How about:

select user,
       avg(case when mark > 0 then mark end),
       sum(mark)
from   ...
like image 29
David Aldridge Avatar answered Sep 30 '22 04:09

David Aldridge