从同一个表中选择不同的计数

And*_*ean 1 oracle

我在 Oracle DB 上有表 T_LOCATION_DATA,如下所示:

Person_ID | Location | Role
----------------------------
101         Delhi      Manager
102         Mumbai     Employee
103         Noida      Manager
104         Mumbai     Employee
105         Noida      Employee
106         Delhi      Manager
107         Mumbai     Manager
108         Delhi      Employee
109         Mumbai     Employee
Run Code Online (Sandbox Code Playgroud)

另一个表是 T_STATUS,其中包含以下数据:

Person_ID | Status
-------------------
101         Active
102         Active
103         Inactive
104         Active
105         Active
106         Inactive      
107         Active     
108         Active
109         Inactive
Run Code Online (Sandbox Code Playgroud)

我正在尝试获取活跃的员工和经理的数量;在单个查询中按位置分组,结果如下:

Location  |   MANAGER COUNT |  EMPLOYEE COUNT
Delhi         1                1
Mumbai        1                1
Noida         0                1
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用以下查询但没有结果:

select location, count (a.person_id) as MANAGER COUNT, 
                 count (b.person_id) as EMPLOYEE COUNT 
from   T_LOCATION_DATA a,T_LOCATION_DATA b 
where  a.person_id in (select person_id from t_status where status='Active')
Run Code Online (Sandbox Code Playgroud)

......我在这里迷路了

有人可以指导我吗?

Cai*_*ard 5

根据您的数据,我会这样查询:

SELECT 
  Location,
  COUNT(CASE WHEN Role='Manager' THEN 1 END) as count_managers,
  COUNT(CASE WHEN Role='Employee' THEN 1 END) as count_employees,
  COUNT(*) count_everyone
FROM
  t_location_data l 
  INNER JOIN 
  t_status s
  ON
    l.person_id = s.person_id AND
    s.status = 'Active'
GROUP BY location
Run Code Online (Sandbox Code Playgroud)

与您的 SQL 的差异:

我们抛弃了糟糕的旧连接语法 ( SELECT * FROM a,b WHERE a.id=b.id) - 请始终使用a JOIN b ON a.id = b.id

我们加入状态表,但我们只对活动表真正这样做,因此我将其作为 ON 中的另一个子句声明的原因。我可以把它放在一个WHERE. 与INNER JOIN它没有区别。使用OUTER JOIN它可以产生很大的不同,就好像您编写的a LEFT JOIN b ON a.id = b.id WHERE b.id = 'active'内容会将 LEFT JOIN 转换回 INNER JOIN 行为,除非您创建了一个 where 子句,例如WHERE b.id = 'active' OR b.id IS NULL- 这很丑陋。如果将与常量的比较放在 ON 子句中,则可以跳过or ... is null丑陋

我们按位置分组,但我们不一定计算所有内容。如果我们计算 a 的结果CASE WHEN role = 'Manager' THEN ...,那么当为管理器产生 1 时,它为非管理器产生 NULL(我没有为 else 指定任何内容;这是 CASE WHEN 在这种情况下的设计行为) . 数字也不必是 1;可能是'a'Role;任何非空的东西。COUNT 将任何非 null 计数为 1,将 null 计数为 0。因此以下是等效的,选择对您更有意义的那个:

COUNT(CASE WHEN Role='Employee' THEN 1 END) as count_employees,
COUNT(CASE WHEN Role='Employee' THEN 'a' END) as count_employees,
COUNT(CASE WHEN Role='Employee' THEN role END) as count_employees,
COUNT(CASE WHEN Role='Employee' THEN role ELSE null END) as count_employees,
SUM(CASE WHEN Role='Employee' THEN 1 ELSE 0 END) as count_employees,
Run Code Online (Sandbox Code Playgroud)

它们都用作计数,但在 SUM 的情况下,如果您希望输出数字是计数,则确实必须使用 1 和 0。实际上,0 是可选的,因为 SUM 不会对空值求和(但正如 mathguy 在下面指出的那样,如果您没有输入 ELSE 0,那么当有 0 个项目时,SUM 方法将产生一个 NULL,而不是一个 0。这是否对您有帮助或阻碍是由您自己做出的决定)

我不清楚经理是否也是员工。对我来说,他们是,也许对你不是。我添加了一个 COUNT(*) 来计算该位置的每个人。任何差异意味着 count_employees+count_managers != count_everyone 意味着表中有另一个角色,不是经理或员工.. 选择你的毒药

这种COUNT/SUM(CASE WHEN...)模式对于翻转数据非常有用 - PIVOT 操作。它需要一列数据:

Manager
Employee
Manager
Run Code Online (Sandbox Code Playgroud)

并将其变成两列,用于计数值:

Manager Employee
2       1
Run Code Online (Sandbox Code Playgroud)

您可以根据需要多次扩展它。如果您有 10 个角色,请创建 10 个 case whens,结果将包含 10 个分组计数的列。数据从 row-ar 表示转换为 column-ar 表示