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);