PostgreSQL 9.3:数据透视 table 查询
PostgreSQL 9.3: Pivot table query
我想显示下面给定的 table(交叉表)的数据透视表 table。
Table: Employee
CREATE TABLE Employee
(
Employee_Number varchar(10),
Employee_Role varchar(50),
Group_Name varchar(10)
);
插入:
INSERT INTO Employee VALUES('EMP101','C# Developer','Group_1'),
('EMP102','ASP Developer','Group_1'),
('EMP103','SQL Developer','Group_2'),
('EMP104','PLSQL Developer','Group_2'),
('EMP101','Java Developer',''),
('EMP102','Web Developer','');
现在我想显示上述数据的枢轴table,如下所示:
预期结果:
Employee_Number TotalRoles TotalGroups Available Others Group_1 Group_2
---------------------------------------------------------------------------------------------------
EMP101 2 2 1 1 1 0
EMP102 2 2 1 1 1 0
EMP103 1 2 1 0 0 1
EMP104 1 2 1 0 0 1
说明:我想展示每个员工拥有的Employee_Number
,TotalRoles
,
TotalGroups
显示给所有员工,Available
显示可用的员工
在多少个组中,Others
必须显示该员工在其他人中也有空
group_name 尚未分配,最后 Group_Names
必须以数据透视格式显示。
您可以为此使用 crosstab 函数。
首先你需要添加 tablefunc 扩展,如果你还没有的话:
CREATE EXTENSION tablefunc;
交叉表函数要求您向其传递一个查询,该查询返回您需要转换的数据,然后是输出中的列列表。 (在其他方面 "tell me the input and the output format you want")。排序顺序很重要!
在您的情况下,输入查询非常复杂 - 我认为您需要执行大量单独的查询,然后将它们联合起来以获得所需的数据。我不完全确定你如何计算值 "TotalGroups" 和 "Available",但你可以在相关位置修改以下内容以获得你需要的内容。
SELECT * FROM crosstab(
'SELECT employee_number, attribute, value::integer AS value FROM (with allemployees AS (SELECT distinct employee_number FROM employee) -- use a CTE to get distinct employees
SELECT employee_number,''attr_0'' AS attribute,COUNT(distinct employee_role) AS value FROM employee GROUP BY employee_number -- Roles by employee
UNION ALL
SELECT employee_number,''attr_1'' AS attribute,value from allemployees, (select count (distinct group_name) as value from employee where group_name <> '''') a
UNION ALL
SELECT employee_number,''attr_2'' AS attribute, COUNT(distinct group_name) AS value FROM employee where group_name <> '''' GROUP BY employee_number -- Available, do not know how this is calculate
UNION ALL
SELECT a.employee_number, ''attr_3'' AS attribute,coalesce(value,0) AS value FROM allemployees a LEFT JOIN -- other groups. Use a LEFT JOIN to avoid nulls in the output
(SELECT employee_number,COUNT(*) AS value FROM employee WHERE group_name ='''' GROUP BY employee_number) b on a.employee_number = b.employee_number
UNION ALL
SELECT a.employee_number, ''attr_4'' AS attribute,coalesce(value,0) AS value FROM allemployees a LEFT JOIN -- group 1
(SELECT employee_number,COUNT(*) AS value FROM employee WHERE group_name =''Group_1'' GROUP BY employee_number) b on a.employee_number = b.employee_number
UNION ALL
SELECT a.employee_number, ''attr_5'' AS attribute,coalesce(value,0) AS value FROM allemployees a LEFT JOIN -- group 2
(SELECT employee_number,COUNT(*) AS value FROM employee WHERE group_name =''Group_2'' GROUP BY employee_number) b on a.employee_number = b.employee_number) a order by 1,2')
AS ct(employee_number varchar,"TotalRoles" integer,"TotalGroups" integer,"Available" integer, "Others" integer,"Group_1" integer, "Group_2" integer)
SELECT * FROM crosstab(
$$SELECT grp.*, e.group_name
, CASE WHEN e.employee_number IS NULL THEN 0 ELSE 1 END AS val
FROM (
SELECT employee_number
, count(employee_role)::int AS total_roles
, (SELECT count(DISTINCT group_name)::int
FROM employee
WHERE group_name <> '') AS total_groups
, count(group_name <> '' OR NULL)::int AS available
, count(group_name = '' OR NULL)::int AS others
FROM employee
GROUP BY 1
) grp
LEFT JOIN employee e ON e.employee_number = grp.employee_number
AND e.group_name <> ''
ORDER BY grp.employee_number, e.group_name$$
,$$VALUES ('Group_1'::text), ('Group_2')$$
) AS ct (employee_number text
, total_roles int
, total_groups int
, available int
, others int
, "Group_1" int
, "Group_2" int);
SQL Fiddle 演示基本查询,但不演示 sqlfiddle.com
上未安装的交叉表步骤
交叉表基础知识:
- PostgreSQL Crosstab Query
此交叉表的特殊之处:所有 "extra" 列。这些列放在中间,在 "row name" 之后但在 "category" 和 "value" 之前:
- Pivot on Multiple Columns using Tablefunc
再次重申,如果您有一组动态组,则需要动态构建此语句并在第二次调用中执行它:
- Selecting multiple max() values using a single SQL statement
我想显示下面给定的 table(交叉表)的数据透视表 table。
Table: Employee
CREATE TABLE Employee
(
Employee_Number varchar(10),
Employee_Role varchar(50),
Group_Name varchar(10)
);
插入:
INSERT INTO Employee VALUES('EMP101','C# Developer','Group_1'),
('EMP102','ASP Developer','Group_1'),
('EMP103','SQL Developer','Group_2'),
('EMP104','PLSQL Developer','Group_2'),
('EMP101','Java Developer',''),
('EMP102','Web Developer','');
现在我想显示上述数据的枢轴table,如下所示:
预期结果:
Employee_Number TotalRoles TotalGroups Available Others Group_1 Group_2
---------------------------------------------------------------------------------------------------
EMP101 2 2 1 1 1 0
EMP102 2 2 1 1 1 0
EMP103 1 2 1 0 0 1
EMP104 1 2 1 0 0 1
说明:我想展示每个员工拥有的Employee_Number
,TotalRoles
,
TotalGroups
显示给所有员工,Available
显示可用的员工
在多少个组中,Others
必须显示该员工在其他人中也有空
group_name 尚未分配,最后 Group_Names
必须以数据透视格式显示。
您可以为此使用 crosstab 函数。
首先你需要添加 tablefunc 扩展,如果你还没有的话:
CREATE EXTENSION tablefunc;
交叉表函数要求您向其传递一个查询,该查询返回您需要转换的数据,然后是输出中的列列表。 (在其他方面 "tell me the input and the output format you want")。排序顺序很重要!
在您的情况下,输入查询非常复杂 - 我认为您需要执行大量单独的查询,然后将它们联合起来以获得所需的数据。我不完全确定你如何计算值 "TotalGroups" 和 "Available",但你可以在相关位置修改以下内容以获得你需要的内容。
SELECT * FROM crosstab(
'SELECT employee_number, attribute, value::integer AS value FROM (with allemployees AS (SELECT distinct employee_number FROM employee) -- use a CTE to get distinct employees
SELECT employee_number,''attr_0'' AS attribute,COUNT(distinct employee_role) AS value FROM employee GROUP BY employee_number -- Roles by employee
UNION ALL
SELECT employee_number,''attr_1'' AS attribute,value from allemployees, (select count (distinct group_name) as value from employee where group_name <> '''') a
UNION ALL
SELECT employee_number,''attr_2'' AS attribute, COUNT(distinct group_name) AS value FROM employee where group_name <> '''' GROUP BY employee_number -- Available, do not know how this is calculate
UNION ALL
SELECT a.employee_number, ''attr_3'' AS attribute,coalesce(value,0) AS value FROM allemployees a LEFT JOIN -- other groups. Use a LEFT JOIN to avoid nulls in the output
(SELECT employee_number,COUNT(*) AS value FROM employee WHERE group_name ='''' GROUP BY employee_number) b on a.employee_number = b.employee_number
UNION ALL
SELECT a.employee_number, ''attr_4'' AS attribute,coalesce(value,0) AS value FROM allemployees a LEFT JOIN -- group 1
(SELECT employee_number,COUNT(*) AS value FROM employee WHERE group_name =''Group_1'' GROUP BY employee_number) b on a.employee_number = b.employee_number
UNION ALL
SELECT a.employee_number, ''attr_5'' AS attribute,coalesce(value,0) AS value FROM allemployees a LEFT JOIN -- group 2
(SELECT employee_number,COUNT(*) AS value FROM employee WHERE group_name =''Group_2'' GROUP BY employee_number) b on a.employee_number = b.employee_number) a order by 1,2')
AS ct(employee_number varchar,"TotalRoles" integer,"TotalGroups" integer,"Available" integer, "Others" integer,"Group_1" integer, "Group_2" integer)
SELECT * FROM crosstab(
$$SELECT grp.*, e.group_name
, CASE WHEN e.employee_number IS NULL THEN 0 ELSE 1 END AS val
FROM (
SELECT employee_number
, count(employee_role)::int AS total_roles
, (SELECT count(DISTINCT group_name)::int
FROM employee
WHERE group_name <> '') AS total_groups
, count(group_name <> '' OR NULL)::int AS available
, count(group_name = '' OR NULL)::int AS others
FROM employee
GROUP BY 1
) grp
LEFT JOIN employee e ON e.employee_number = grp.employee_number
AND e.group_name <> ''
ORDER BY grp.employee_number, e.group_name$$
,$$VALUES ('Group_1'::text), ('Group_2')$$
) AS ct (employee_number text
, total_roles int
, total_groups int
, available int
, others int
, "Group_1" int
, "Group_2" int);
SQL Fiddle 演示基本查询,但不演示 sqlfiddle.com
上未安装的交叉表步骤交叉表基础知识:
- PostgreSQL Crosstab Query
此交叉表的特殊之处:所有 "extra" 列。这些列放在中间,在 "row name" 之后但在 "category" 和 "value" 之前:
- Pivot on Multiple Columns using Tablefunc
再次重申,如果您有一组动态组,则需要动态构建此语句并在第二次调用中执行它:
- Selecting multiple max() values using a single SQL statement