Today, when I use Postgres database to write sql, I found an error after execution: column “XXXXXX” must appear in the GROUP BY clause or be used in an aggregate function. After putting the query fields into groups according to the prompts, the results of the query are not what I need. Yes, I checked the solution on the Internet, hereby record
The cause of the problem: This is a common aggregation problem in pgsql. Before the SQL3 standard, the field selected for display must appear in GROUP BY
the
Assuming that there is a makerar table, the data is as follows:
cname | wmname | avg --------+-------------+------------------------ canada | zoro | 2.0000000000000000 spain | luffy | 1.00000000000000000000 spain | usopp | 5.0000000000000000
I would like tocname grouping query to avg value of the largest data, sql as follows
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;
However, error
ERROR: column "makerar.wmname" must appear in the GROUP BY clause or be used in an aggregate function LINE 1: SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname;
So, I putAfter the group that wmname joined
SELECT cname, wmname, MAX(avg) FROM makerar GROUP BY cname, wmname;
The result is as follows, but this is not the data I want
cname | wmname | max --------+--------+------------------------ canada | zoro | 2.0000000000000000 spain | luffy | 1.00000000000000000000 spain | usopp | 5.0000000000000000
My desired data result is
cname | wmname | max --------+--------+------------------------ canada | zoro | 2.0000000000000000 spain | usopp | 5.0000000000000000
There are two ways to solve this problem:
1. Using nested sql, compute the aggregate in a subquery, then join it with itself to get the additional columns that need to be displayed
SELECT m.cname, m.wmname, t.mx FROM ( SELECT cname, MAX(avg) AS mx FROM makerar GROUP BY cname ) t JOIN makerar m ON m.cname = t.cname AND t.mx = m.avg ; cname | wmname | mx --------+--------+------------------------ canada | zoro | 2.0000000000000000 spain | usopp | 5.0000000000000000
2. Use the special DISTINCT ON expression
SELECT DISTINCT ON (cname) cname, wmname, avg FROM makerar ORDER BY cname, avg DESC ;
Combined with your own business, use the first method to transform sql
SELECT pihs.pat_status, b.bed_class_id, pih.charge_class_id, pihs.pat_condition, pih.pat_id, pihs.room_with_mother_baby_flag, pc.pat_in_charge_doc_name, pc.pat_in_charge_doc_id, b.bed_show_no, pih.pat_age AS age, pih.pat_in_hos_id, pih.pat_in_hos_code, pihs.pat_in_status, pc.state_of_critical_value, pih.pat_in_time, pc.chief_doc_id, pc.chief_doc_name, pc.dur_nurse_id, pc.dur_nurse_name, pc.first_ann_bed_time, pc.manage_bed_nurse_name, pih.pat_type_id, pc.pat_clinic_id, pc.pat_ward_id, b.bed_id, b.bed_status, b.is_share, pc.nursing_class, pc.nursing_class_name, pihs.pat_in_bed_share_status, pih.seven_days_again_in_flag, b.price, T.change_in_time FROM bed b LEFT JOIN pat_in_hospital_status pihs ON b.bed_id = pihs.bed_id LEFT JOIN pat_in_hospital pih ON b.pat_in_hos_id = pih.pat_in_hos_id LEFT JOIN pat_clinican pc ON pih.pat_in_hos_id = pc.pat_in_hos_id LEFT JOIN ( SELECT pat_in_hos_id, MAX ( pat_in_out_ward_time ) AS change_in_time FROM change_ward_record WHERE complete_flag = '1' GROUP BY pat_in_hos_id ) T ON pih.pat_in_hos_id = T.pat_in_hos_id where b.ward_id='1234'
Reference link: