目标:返回按角色或某些角色排除在日期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方法可以执行此操作,还是应该返回循环/后处理或临时表?
我正在寻找效率,因为这些表将有数百万行。
答案 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')