Oracle SQL:从一个表中选择一个计数,使用另一个表

时间:2016-09-08 04:26:18

标签: sql oracle

目标:返回按角色或某些角色排除在日期X登录的人数。

我过去通过各种方式做到了这一点,通常选择我想要的,然后使用应用程序语言(php等)循环结果集,查询第二个表。我正在寻找一种更有效,也许是纯粹的SQL方式来做到这一点。

LoginTable
+--------------------+
| userName loginDate |
+--------------------+
| jason 08/15/16     |
| jason 09/01/16     |
| john 08/15/16      |
| john 09/04/16      |
| cindy 08/15/16     |
+--------------------+
RoleTable
+--------------------+
| userName role|
+--------------------+
| jason admin        |
| jason student      |
| jason employee     |
| john  employee     |
| john admin         |
| cindy student      |
| cindy hr           |
| cindy finance      |
+--------------------+

有没有纯粹的oracle SQL方法,而不需要进一步的后处理?

例如,一个问题可能是: 谁在2016年8月15日登录,谁具有员工角色,但没有学生角色。

答案应该是约翰。

从LoginTable中选择userName 其中loginDate = 08/15/16和LoginTable.userName in(从RoleTable中选择userName,其中role = employee and role<> student)

该查询当然不起作用。

是否有一种纯粹的SQL方法可以执行此操作,还是应该返回循环/后处理或临时表?

我正在寻找效率,因为这些表将有数百万行。

2 个答案:

答案 0 :(得分:2)

<强>更新

以下是更新后问题的答案,该问题与最初提出的问题(q.v.)大不相同

您可以对RoleTable中的用户使用条件聚合来确定哪些用户具有employee角色但不具有student角色。然后,您可以进一步将此限制为登录08/15/16的用户:

SELECT t1.userName
FROM RoleTable t1
INNER JOIN LoginTable t2
    ON t1.userName = t2.userName
WHERE t1.loginDate = TO_DATE('08/15/16', 'DD/MM/YY')
GROUP BY t1.userName
HAVING SUM(CASE WHEN t1.role = 'employee' THEN 1 ELSE 0 END) > 0 AND
       SUM(CASE WHEN t1.role = 'student'  THEN 1 ELSE 0 END) = 0

注意:自从我第一次给出这个答案以来,问题发生了重大变化。最初的问题是给每个角色登记某个特定日期的学生数量。

SELECT t1.role,
       SUM(CASE WHEN t2.userName IS NOT NULL THEN 1 ELSE 0 END) AS peopleCount
FROM RoleTable t1
LEFT JOIN LoginTable t2
    ON t1.userName = t2.userName
WHERE t1.loginDate = '08/15/16'
GROUP BY t1.role

答案 1 :(得分:1)

SELECT DISTINCT userName 
  FROM LoginTable 
 WHERE loginDate = TO_DATE('08/15/16', 'DD/MM/YY')
    -- include
   AND userName IN (SELECT userName FROM RoleTable WHERE role = 'employee')
    -- exclude
   AND userName NOT IN (SELECT userName FROM RoleTable WHERE role = 'student')