PostgreSQL 9.3:数据透视表查询
我想显示下表的透视表交叉表 表:雇员 插入:PostgreSQL 9.3:数据透视表查询,sql,postgresql,pivot-table,postgresql-9.3,table-functions,Sql,Postgresql,Pivot Table,Postgresql 9.3,Table Functions,我想显示下表的透视表交叉表 表:雇员 插入: INSERT INTO Employee VALUES('EMP101','C# Developer','Group_1'), ('EMP102','ASP Developer','Group_1'), ('EMP103','SQL Developer','Group_2'), ('EMP1
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','');
现在,我想显示上述数据的透视表,如下所示:
预期结果:
说明:我想显示员工编号,每个员工的总角色,
向所有员工显示的TotalGroup,Available(可用)显示可用员工
在多少组中,其他人必须表明该员工在其他人的哪些组中可用
尚未分配组名称,最后必须以透视格式显示组名称 您可以使用该函数来完成此操作
首先,如果尚未添加tablefunc扩展,则需要添加该扩展:
CREATE EXTENSION tablefunc;
交叉表函数要求您向其传递一个查询,返回需要透视的数据,然后是输出中的列列表。在其他方面告诉我你想要的输入和输出格式。排序顺序很重要
在您的例子中,输入查询相当复杂-我认为您需要执行大量单独的查询,然后合并所有查询以获得所需的数据。我不完全确定如何计算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)
演示基本查询,但不演示交叉表步骤,该步骤未安装在sqlfiddle.com上
交叉表的基础知识:
这个交叉表中的特殊点:所有额外的列。这些列放置在中间,在行名称之后,但在类别和值之前:
同样,如果您有一组动态组,则需要动态构建此语句,并在第二次调用中执行它:
问题是什么?问题在解释上。但我真的不明白最后4列calculating@Houari我只看到预期的结果,而不是问题或问题。如果我只想显示要显示的组名称的选定数量,那么如何计算该组名称的可用数量?我尝试过这样的方法:当“group_1”中的group_name出现时,从SELECT CASE中选择countavailable,然后按group_name从employee group中选择1作为available,然后按group_name a作为available代替countgroup_name或NULL::int作为available,但没有得到正确的结果。@MAK:这是一个新问题。如果你被这个问题困住了,请开始一个新问题。和往常一样,你可以链接到这一个作为上下文。看看。如果我在员工值中插入'EMP101','C Developer','Group_1';同一条语句多次出现。在此之后,如果我执行您的脚本,那么可用的脚本将得到更改。请看看这个。谢谢:
CREATE EXTENSION tablefunc;
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);