我可能想过这个,因为我不确定从哪里开始......但是这里有:
我有以下
生
评估
students_assessments
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
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
绊倒我的部分并没有为每个评估进行连接,甚至没有手动定义列,而是“生成”每列用于存在的评估。
我觉得这很简单,而且我现在太过于劳累而无法弄明白:)请事先感谢您的帮助,这里有一个SQL Fiddle数据作为示例
答案 0 :(得分:1)
简单查询“尝试”,
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
在crosstab()函数中,还需要明确定义列名称,如“评估1”,“评估2”等。
或编写用于创建动态查询的自定义函数,并使用EXECUTE语句执行。
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();
第二次查询“已通过”
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
它的功能看起来像,
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();
答案 1 :(得分:0)
SELECT * FROM crosstab( '选择studentid,assessmentname,count(studentassessmentid)来自.... [你在这里加入] group by studentid,assessmentname order by 1,2' AS ct(studentid,assesment1,assessment2,assesent3,assessment4);
答案 2 :(得分:0)
我意识到它不再起作用了。我正在使用 PostgreSQL 12。 所以在这里你不能返回非预定义的表类型(我的意思是变量列)或者从不同的字符中选择。
使用匿名代码块、交叉表和临时表的示例。 光标是多余的,我正在解决一个需要使用它们的任务。
CREATE EXTENSION IF NOT EXISTS tablefunc;
DO
$$
DECLARE
movie_probe CURSOR FOR
SELECT m.name movie_name, count(c.id) cinema_count
FROM movies m
JOIN sessions s ON m.id = s.movie_id
JOIN cinema_halls ch ON s.cinema_hall_id = ch.id
JOIN cinemas c ON ch.cinema_id = c.id
GROUP BY m.name
HAVING count(c.name) > 1
ORDER BY count(c.name) DESC;
movie_rec RECORD;
movie_columns TEXT DEFAULT '';
cinemas_probe CURSOR (cond_movie_name TEXT) FOR
SELECT m.name movie_name, c.name cinema_name
FROM movies m
JOIN sessions s ON m.id = s.movie_id
JOIN cinema_halls ch ON s.cinema_hall_id = ch.id
JOIN cinemas c ON ch.cinema_id = c.id
WHERE cond_movie_name = m.name
ORDER BY c.name;
cinema_rec RECORD;
cinema_row_counter INT DEFAULT 0;
BEGIN
DROP TABLE IF EXISTS cinema_multiples_aev;
CREATE TEMP TABLE cinema_multiples_aev (
row_id INT,
movie_name TEXT,
cinema_name TEXT
);
OPEN movie_probe;
LOOP
FETCH movie_probe INTO movie_rec;
EXIT WHEN NOT FOUND;
OPEN cinemas_probe(movie_rec.movie_name);
LOOP
FETCH cinemas_probe INTO cinema_rec;
EXIT WHEN NOT FOUND;
cinema_row_counter := cinema_row_counter + 1;
INSERT INTO cinema_multiples_aev (row_id, movie_name, cinema_name)
VALUES (cinema_row_counter, cinema_rec.movie_name, cinema_rec.cinema_name);
END LOOP;
CLOSE cinemas_probe;
cinema_row_counter := 0;
movie_columns := movie_columns || ', "' || movie_rec.movie_name || '" TEXT';
END LOOP;
CLOSE movie_probe;
movie_columns := substring(movie_columns FROM 2);
DROP TABLE IF EXISTS movie_multiples;
EXECUTE format('CREATE TEMP TABLE movie_multiples(row_id INT, %s)', movie_columns);
EXECUTE format(E'
INSERT INTO movie_multiples
SELECT *
FROM crosstab(\'select row_id, movie_name, cinema_name
from cinema_multiples_aev
order by 1,2\')
AS cinema_multiples_aev(row_id INT, %s);
', movie_columns, movie_columns);
ALTER TABLE movie_multiples DROP COLUMN row_id;
END
$$ LANGUAGE plpgsql;
SELECT *
FROM movie_multiples;
DROP TABLE IF EXISTS movie_multiples;
DROP TABLE IF EXISTS cinema_multiples_aev;
如果因为缺乏信任而感到困惑,一切都可以在这里找到github