用一个学生注册课程的实例来演示如何实现动态行列表
运行环境:PostgreSQL 9.6, psql 客户端
studentid |
firstname |
lastname |
1 |
Anne |
Lee |
2 |
Sarah |
Christian |
3 |
John |
Smith |
studentid |
course |
1 |
Operational System (CS501) |
1 |
Compiler (CS401) |
1 |
DataStructure (CS101) |
2 |
Operational System (CS501) |
2 |
DataStructure (CS101) |
3 |
Compiler (CS401) |
3 |
DataStructure (CS101) |
CREATE TABLE Students (StudentID INT PRIMARY KEY, FirstName TEXT, LastName TEXT);
INSERT INTO Students
VALUES
(1, 'Anne', 'Lee'),
(2, 'Sarah', 'Christian'),
(3, 'John', 'Smith');
CREATE TABLE Registration (StudentId INT, Course TEXT);
INSERT INTO Registration
VALUES
(1,'Operational System (CS501)'),
(1,'Compiler (CS401)'),
(1,'DataStructure (CS101)'),
(2,'Operational System (CS501)'),
(2,'DataStructure (CS101)'),
(3,'Compiler (CS401)'),
(3,'DataStructure (CS101)');
- 下面的转换表可以用crosstab 直接实现
studentid |
Operational System (CS501) |
Compiler (CS401) |
DataStructure (CS101) |
1 |
x |
x |
x |
2 |
|
x |
x |
3 |
x |
x |
|
SELECT StudentId,
"Operational System (CS501)", "Compiler (CS401)", "DataStructure (CS101)"
FROM CROSSTAB (
$x$ SELECT StudentId, Course, 'x' FROM Registration ORDER BY 1 $x$,
$y$ SELECT DISTINCT Course FROM Registration ORDER BY 1 $y$
) AS (
StudentId INT, "Operational System (CS501)" TEXT,
"Compiler (CS401)" TEXT, "DataStructure (CS101)" TEXT);
- 运用array可以输出下面的结果, 添加了行 Student Name
studentid |
studentname |
Operational System (CS501) |
Compiler (CS401) |
DataStructure (CS101) |
1 |
Anne Lee |
x |
x |
x |
2 |
Sarah Christian |
|
x |
x |
3 |
John Smith |
x |
x |
|
SELECT name[1] AS StudentId, name[2] || ' ' || name[3] AS StudentName,
"Operational System (CS501)", "Compiler (CS401)", "DataStructure (CS101)"
FROM CROSSTAB (
$x$ SELECT array[StudentId::TEXT, FirstName::TEXT, LastName::TEXT] AS Name, Course, 'x'
FROM Registration JOIN Students USING (StudentId) ORDER BY 1
$x$,
$y$ SELECT DISTINCT Course FROM Registration ORDER BY 1 $y$
) AS (
name TEXT[],
"Operational System (CS501)" TEXT, "Compiler (CS401)" TEXT, "DataStructure (CS101)" TEXT);
- 用do block, json query, dynamic sql 动态生成表头,在有大量数据的情况下尤其适用。需要注意的是do block的结果不能直接显示在console,在do block将结果置入temp table, 运行结束后再从temp table 中去获取表格
DO $$
DECLARE
_colname TEXT; _retname TEXT; _query TEXT;
BEGIN
SELECT INTO _colname
array_to_string(
array_agg(
'"' || Course || '"'
ORDER BY Course),',')
FROM (SELECT Distinct Course FROM Registration) q;
SELECT INTO _retname array_to_string(array_agg('"' || Course || '" TEXT'
ORDER BY Course),',')
FROM (SELECT Distinct Course FROM Registration) q;
_query = 'SELECT name[1] AS StudentId, name[2] AS StudentName,'
|| _colname ||
$w$
FROM CROSSTAB (
$x$
SELECT array[r.StudentId::TEXT, s.FirstName || ' ' || s.LastName] AS Name,
r.Course, 'x'
FROM Registration r JOIN Students s USING (StudentId)
ORDER BY 1
$x$,
$y$
SELECT DISTINCT Course FROM Registration
ORDER BY 1
$y$
)
AS (
name TEXT[],
$w$ || _retname || ') ORDER BY 1,2;';
EXECUTE 'CREATE TEMP TABLE test AS ' || _query;
END;
$$;