Find max in group by in postgresql - postgresql

This is my students table. I want to display the hostel,rollno,parent_inc of the student who has the max(parent_inc) in a hostel. When I'm trying this command -
select hostel, rollno, max(parent_inc) from students group by hostel;
Getting error -
column "students.rollno" must appear in the GROUP BY clause or be used in an aggregate function
select hostel, rollno, max(parent_inc) from students group b...
How to get it in correct way?
Without selecting rollno field it works fine.

Try the windowed version of MAX function:
select rollno
, hostel
, max(parent_inc) over(partition by hostel) max_parent_inc
from students;
NOTE: Not tested

Related

How to get latest data for a column when using grouping in postgres

I am using postgres alongside sequelize. I have encountered a case where I need to write a coustom query which groups the records are a particular field. I know for the remaning columns that are not used for grouping, I need to use a aggregate function like SUM. But the problem is that for some columns I need to get the one what is the latest one (DESC sorted by created_at). I see no function in sql to do so. Is my only option to write subqueries or is there a better way? Thanks?
For better understanding, If you look at the below picture, I want the group the records with address. So after the query there should only be two records, one with sydney and the other with new york. But when it comes to the distance, I want the result of the query to contain the distance form the row that was most recently created, i.e with the latest created_at.
so the final two query results should be:
sydney 100 2022-09-05 18:14:53.492131+05:45
new york 40 2022-09-05 18:14:46.23328+05:45
select address, distance, created_at
from(
select address, distance, created_at, row_number() over(partition by address order by created_at DESC) as rn
from table) x
where rn = 1

Postgres Select one record per matching condition

I have some issues while trying to get only one record per matching condition..
Let's suppose I have Certifications table with the following columns:
Id, EmployeeId, DepartmentId, CertificationTitle, PassedDate
An employee can have more then one record in this table but I need to get only one record per employee (based on latest PassedDate)
SELECT Id, EmployeeId, CertificationTitle
FROM certifications c
ORDER BY EmployeeId, PassedDate DESC
From this select I need somehow to get only the first record for each EmployeeId.
Does anyone have any ideas how I can achieve this, Is it possible?
The Id is the Primary Key on the table, so it is different on each record.
I need to keep all this columns specified in the Select query.
The Group By didn't worked for me, or maybe I did it wrong...
Use DISTINCT ON. This returns exactly the first ordered record of the group. You ordered correctly by PassedData DESC to get the most recent record first. The group for DISTINCT ON, naturally, is EmployeeID:
SELECT DISTINCT ON (EmployeeId),
Id,
EmployeeId,
CertificationTitle
FROM certifications c
ORDER BY EmployeeId, PassedDate DESC

Column must appear in the GROUP BY clause

I have this query:
SELECT
"EventReadingListItem"."id"
, "EventReadingListItem"."UserId"
FROM "EventReadingListItems" AS "EventReadingListItem"
group by "EventReadingListItem"."EventId";
When I run it I get the error
Column "EventReadingListItem"."id" must appear in the GROUP BY clause or be used in an aggregate function.
Why? I have read similar questions but I don't really get why this simple group by is not working. Is it because the field in group by is not known as "EventReadingListItem" yet?
So, according to your comment, this should work for you.
Gives unique rows for each EventId which does have smallest/min id value:
select DISTINCT ON (EventId) EventId, id, UserId
from EventReadingListItems
order by EventId, id

Getting group by attribute in nested query

I am trying to find the most frequent value in a postgresql table. The problem is that I also want to "group by" in that table and only get the most frequent from the values that have the same name.
So I have the following query:
select name,
(SELECT value FROM table where name=name GROUP BY value ORDER BY COUNT(*) DESC limit 1)
as mfq from table group by name;
So, I am using where name=name, trying to get the outside group by attribute "name", but it doesn't seem to work. Any ideas on how to do it?
Edit: for example in the following table:
name value
a 3
a 3
a 3
b 2
b 2
I want to get:
name value
a 3
b 2
but the above statement gives:
name value
a 3
b 3
instead, since where doesn't work correctly.
There is a dedicated function in PostgreSQL for this case: the mode() ordered-set aggregate:
select name, mode() within group (order by value) mode_value
from table
group by name;
which returns the most frequent input value (arbitrarily choosing the first one if there are multiple equally-frequent results) -- which is the same behavior as with your order by count(*) desc limit 1.
It is available from PostgreSQL 9.4+.
http://rextester.com/GHGJH15037
If you want your query to work, you need table aliases. Table aliases and qualified column names are always a good idea:
select t.name,
(select t2.value
from table t2
where t2.name = t.name
group by t2.value
order by COUNT(*) desc
limit 1
) as mfq
from table t
group by t.name;

group by date aggregate function in postgresql

I'm getting an error running this query
SELECT date(updated_at), count(updated_at) as total_count
FROM "persons"
WHERE ("persons"."updated_at" BETWEEN '2012-10-17 00:00:00.000000' AND '2012-11-07 12:25:04.082224')
GROUP BY date(updated_at)
ORDER BY persons.updated_at DESC
I get the error ERROR: column "persons.updated_at" must appear in the GROUP BY clause or be used in an aggregate function LINE 5: ORDER BY persons.updated_at DESC
This works if I remove the date( function from the group by call, however I'm using the date function because i want to group by date, not datetime
any ideas
At the moment it is unclear what you want Postgres to return. You say it should order by persons.updated_at but you do not retrieve that field from the database.
I think, what you want to do is:
SELECT date(updated_at), count(updated_at) as total_count
FROM "persons"
WHERE ("persons"."updated_at" BETWEEN '2012-10-17 00:00:00.000000' AND '2012-11-07 12:25:04.082224')
GROUP BY date(updated_at)
ORDER BY count(updated_at) DESC -- this line changed!
Now you are explicitly telling the DB to sort by the resulting value from the COUNT-aggregate. You could also use: ORDER BY 2 DESC, effectively telling the database to sort by the second column in the resultset. However I highly prefer explicitly stating the column for clarity.
Note that I'm currently unable to test this query, but I do think this should work.
the problem is that, because you are grouping by date(updated_at), the value for updated_at may not be unique, different values of updated_at can return the same value for date(updated_at). You need to tell the database which of the possible values it should use, or alternately use the value returned by the group by, probably one of
SELECT date(updated_at) FROM persons GROUP BY date(updated_at)
ORDER BY date(updated_at)
or
SELECT date(updated_at) FROM persons GROUP BY date(updated_at)
ORDER BY min(updated_at)