PostgreSQL Query with dynamic columns and counts from join

流过昼夜 提交于 2019-12-24 00:49:59

问题


I'm probably overthinking this, because I'm not really sure where to start... But here goes:

I have the following

Tables

students

assessments

students_assessments

Expected output

First query for "Attempts"

student_id | Assessment 1 | Assessment 2 | Assessment 3 | Assessment 4
1            3              1              2              0
2            1              0              0              0
3            2              1              1              0
4            5              3              3              0
5            1              5              0              0
6            2              1              2              0

Second query for "passed"

student_id | Assessment 1 | Assessment 2 | Assessment 3 | Assessment 4
1            t              t              f              f
2            t              t              f              f
3            t              t              f              f
4            t              t              t              f
5            t              t              f              f
6            t              t              t              f

The part that is tripping me up is not doing a join for EVERY assessment, and not even defining the columns manually but rather "generating" each column for assessments that exist.

I feel like it's simple, and I am just too overworked to figure it out right now :) thank you in advance for your help, and here's a SQL Fiddle of data as an example


回答1:


Simple query for "Attempts",

select student_id,sum(case when assessment_id=1 then 1 else 0 end) as "Assessment 1",
sum(case when assessment_id=2 then 1 else 0 end) as "Assessment 2",
sum(case when assessment_id=3 then 1 else 0 end) as "Assessment 3",
sum(case when assessment_id=4 then 1 else 0 end) as "Assessment 4",
sum(case when assessment_id=5 then 1 else 0 end) as "Assessment 5",
sum(case when assessment_id=6 then 1 else 0 end) as "Assessment 6"
from assessments_students
group by student_id
order by student_id

In crosstab() function also, need to define columns name explicitly like "Assessment 1","Assessment 2" and so on.

Or write custom function for creating dynamic query, and execute using EXECUTE statement.

DROP FUNCTION get_Attempts() ;

CREATE OR REPLACE FUNCTION get_Attempts() RETURNS text AS
$BODY$
DECLARE
        r1 record;
        str_query text := '';
 BEGIN
    str_query :='select student_id,';
    FOR r1 IN SELECT "_id" , "name" FROM Assessments
    LOOP
      str_query:= str_query || 
                  'sum(case when assessment_id=' || r1."_id" || ' then 1 else 0 end) as  "' || r1.name ||'",' ;
    END LOOP;
    str_query:=trim( trailing  ',' from str_query); -- remove last semicolon
    str_query:= str_query || ' from assessments_students group by student_id order by student_id';
    return str_query;
END
$BODY$
LANGUAGE 'plpgsql' ;

SELECT * FROM get_Attempts();

Second query for "passed"

select student_id,
max(case when assessment_id=1 and passed='t' then 't' else 'f' end) as  "Assessment 1",
max(case when assessment_id=2 and passed='t' then 't' else 'f' end) as  "Assessment 2",
max(case when assessment_id=3 and passed='t' then 't' else 'f' end) as  "Assessment 3",
max(case when assessment_id=4 and passed='t' then 't' else 'f' end) as  "Assessment 4",
max(case when assessment_id=5 and passed='t' then 't' else 'f' end) as  "Assessment 5",
max(case when assessment_id=6 and passed='t' then 't' else 'f' end) as  "Assessment 6" 
from assessments_students 
group by student_id 
order by student_id

and it's function look likes,

DROP FUNCTION get_passed() ;

CREATE OR REPLACE FUNCTION get_passed() RETURNS text AS
$BODY$
DECLARE
        r1 record;
        str_query text := '';
 BEGIN
    str_query :='select student_id,';
    FOR r1 IN SELECT "_id" , "name" FROM Assessments
    LOOP
      str_query:= str_query || 
                  'max(case when assessment_id=' || r1."_id" || ' and passed=''t'' then ''t'' else ''f'' end) as  "' || r1.name ||'",' ;
    END LOOP;
    str_query:=trim( trailing  ',' from str_query); -- remove last semicolon
    str_query:= str_query || ' from assessments_students group by student_id order by student_id';

    return str_query;
END
$BODY$
LANGUAGE 'plpgsql' ;

SELECT * FROM get_passed();



回答2:


SELECT * FROM crosstab( 'Select studentid, assessmentname,count (studentassessmentid) from ....[do ur joins here] group by studentid,assessmentname order by 1,2' AS ct (studentid, assesment1, assessment2,assesent3,assessment4);



来源:https://stackoverflow.com/questions/33513208/postgresql-query-with-dynamic-columns-and-counts-from-join

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!