Oracle SQL:从一个表中选择一个计数,从另一个表中使用子查询缩小选择范围

Posted

技术标签:

【中文标题】Oracle SQL:从一个表中选择一个计数,从另一个表中使用子查询缩小选择范围【英文标题】:Oracle SQL: select a count from one table, narrow the selection with subquery from another table 【发布时间】:2016-09-08 04:26:17 【问题描述】:

目标:按角色或某些角色排除项返回在日期 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 日登录,谁拥有员工角色,而不是学生角色。

答案应该是约翰。

从登录表中选择用户名 其中 loginDate = 08/15/16 和 LoginTable.userName in(从 RoleTable 中选择用户名,其中角色 = 员工和角色 学生)

这个查询当然是行不通的。

是否有一种纯 sql 方法来执行此操作,或者我应该返回循环/后处理或临时表?

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

【问题讨论】:

编辑,试图把表格弄好。 您更改了问题,从而使我的答案不正确。你不应该那样做。 【参考方案1】:

更新:

这是更新后问题的答案,与最初提出的问题有很大不同(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

【讨论】:

他想要具有指定角色的人名。 @sql_dummy 他在一小时前改变了他的问题。【参考方案2】:
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')

【讨论】:

以上是关于Oracle SQL:从一个表中选择一个计数,从另一个表中使用子查询缩小选择范围的主要内容,如果未能解决你的问题,请参考以下文章

从另一个表中选择一个表的否定以及oracle的主表sql查询中的数据

在一个 sql 命令中从一个数据库表中选择多个计数

从另一个表中选择 * 以及计数/总和

从另一个表中选择具有数据计数的数据[重复]

从另一个表中逐行计数,在sql中的两个表上保存一些条件

从另一个表上的 Where 表中选择计数