PostgreSQL do block, json query, dynamic SQL, crosstab 实现动态行转列透视表 pivot table

用一个学生注册课程的实例来演示如何实现动态行列表
运行环境: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)');
  1. 下面的转换表可以用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);

  1. 运用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);
  1. 用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;
$$;

你可能感兴趣的:(数据库,PostgreSQL,SQL,query)