10

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;

3 Answers 3

27

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"
Sign up to request clarification or add additional context in comments.

Comments

13

How about:

select user,
       avg(case when mark > 0 then mark end),
       sum(mark)
from   ...

1 Comment

Caution to readers: your avg might be wrong if you intend to exclude the row entirely from your list of numbers. @Inego's answer with FILTER WHERE would be better for that scenario.
1
select
    user, -- very bad choice for column name, but i assume it's just SO example, not real column
    sum( mark ) / count (nullif(mark, 0))
from
    table
group by
    user

should so the trick.

2 Comments

is there also possibility how to avoid division by zero in case 'John' has all 'Marks' zero values?
I think I have worked it out sum( mark ) / nullif( count (nullif(mark, 0)),0) Thanks again for your help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.