PostgreSQL 9.3:在数据透视表查询中过滤 [英] PostgreSQL 9.3: Filter in Pivot table query

查看:113
本文介绍了PostgreSQL 9.3:在数据透视表查询中过滤的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,我有这个记录:

  Employee_Number    Employee_role         Group_Name
  ----------------------------------------------------
  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          
  EMP101             DBA          
  EMP105             DBA          
  EMP106             SQL Developer           Group_3      
  EMP107             Oracle Developer        Group_3      
  EMP101             Oracle Developer        Group_3      

要以以下格式显示上述记录的数据透视表:

Want to show the pivot table for above records in the following format:

 Employee_Number     TotalRoles      TotalGroups       Available     Others     Group_1     Group_2      Group_3
 -----------------------------------------------------------------------------------------------------------------
 EMP101                   4               3                2            2          1                        1
 EMP102                   2               3                1            1          1 
 EMP103                   1               3                1            0                      1
 EMP104                   1               3                1            0                      1
 EMP105                   1               3                0            1
 EMP106                   1               3                1            0                                   1
 EMP107                   1               3                1            0                                   1

对于以上结果,我使用以下脚本:

For the above result I am using the following script:

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 employee_number
       ) 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'),('Group_2'),('Group_3')$$
   ) AS ct (employee_number text
      , total_roles  int
      , total_groups int
      , available    int
      , others       int
      , "Group_1"    int
      , "Group_2"    int
      , "Group_3"    int);

但是:现在,我想通过过滤 Group_Name显示上述记录的数据透视表. 这意味着如果我想显示唯一的Group_Name= Group_3的数据透视表,则它具有 仅显示仅属于Group_Name= Group_3的员工.

But:Now I want to show the pivot table for the above records by filtering the Group_Name. That means if I want to show the pivot table for the only Group_Name= Group_3 then it has to show only the employee who is only belongs to the Group_Name= Group_3 not other than that.

如果我只想查看属于Group_3的员工,而不是要向我展示:

If I want to see the employee who is belongs to the Group_3 only than it has to show me:

   Employee_Number    total_roles  total_groups   available    others    Group_3
  ------------------------------------------------------------------------------- 
       EMP106             1             3            1            0            1
       EMP107             1             3            1            0            1

注意:如您在第一张表中所见,员工EMP106EMP107仅属于 到Group_Name = Group_3.员工EMP101也属于,但他也属于其他组 因此不应出现在该表中.

Note: As you can see in the first table the employee EMP106 and EMP107 is only belongs to the Group_Name = Group_3. The employee EMP101 is also belong but he also belongs to other groups so should not appear in this table.

推荐答案

如何排除有问题的行:

crosstab()版本适用于:

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 employee_number
         ) grp
      JOIN   employee e USING (employee_number)
      WHERE  e.group_name = 'Group_3'
      AND    NOT EXISTS (
         SELECT 1 FROM employee
         WHERE  employee_number = e.employee_number
         AND    group_name  e.group_name
         )
      ORDER  BY employee_number$$
   ,$$VALUES ('Group_3')$$
   ) AS ct (employee_number text
      , total_roles  int
      , total_groups int
      , available    int
      , others       int
      , "Group_3"    int);

但是正如您所看到的,我们根本不需要crosstab().简化为:

But as you can see, we don't need crosstab() here at all. Simplify to:

SELECT grp.*, 1 AS "Group_3"
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 employee_number
   ) grp
JOIN   employee e USING (employee_number)
WHERE  e.group_name = 'Group_3'
AND    NOT EXISTS (
   SELECT 1 FROM employee
   WHERE  employee_number = e.employee_number
   AND    group_name <> e.group_name
   )
ORDER  BY employee_number;

"Group_3"列实际上只是杂音,因为根据定义它始终是1.

The column "Group_3" is really just noise here, because it is always 1 by definition.

如果仅以这种方式选择了很小比例的行,则具有LATERAL联接的版本应实质上更快:

If only a small percentage of rows is selected this way, this version with a LATERAL join should be substantially faster:

SELECT e.employee_number
     , grp.total_roles
     , total.total_groups
     , grp.available
     , grp.others
     , 1 AS "Group_3"
FROM  (
   SELECT employee_number
   FROM   employee e
   WHERE  group_name = 'Group_3'
   AND    NOT EXISTS (
      SELECT 1 FROM employee
      WHERE  employee_number = e.employee_number
      AND    group_name <> e.group_name
      )
   ) e
, LATERAL (
   SELECT count(employee_role)::int            AS total_roles
        , count(group_name <> '' OR NULL)::int AS available
        , count(group_name = '' OR NULL)::int  AS others
   FROM   employee
   WHERE  employee_number = e.employee_number
   GROUP  BY employee_number
   ) grp
,    (
   SELECT count(DISTINCT group_name)::int AS total_groups
   FROM   employee
   WHERE  group_name <> ''
   ) total
ORDER  BY employee_number;

LATERAL解决方案和性能的详细信息:

Details for the LATERAL solution and performance:

未针对性能进行优化,但易于调整:

Not optimized for performance, but easy to adapt:

<original crosstab query from your question>
WHERE  "Group_3" = 1
AND    "Group_1" IS NULL
AND    "Group_2" IS NULL
AND    "Group_4" IS NULL
AND    others = 0  -- to rule out membership in the "empty" group
-- possibly more ...

这篇关于PostgreSQL 9.3:在数据透视表查询中过滤的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆