Mysql 如何检查一对多映射表中是否存在特定映射

Mysql 如何检查一对多映射表中是否存在特定映射,mysql,query-performance,Mysql,Query Performance,我有一个表,用于维护员工ID到员工可以分配的一个或多个角色ID的映射。ROLE\u ID是ROLE表的主键 现在,我试图找出某个特定员工是否是团队领导(ROLE_ID=2)。也就是说,本质上,试图找出映射表中是否存在(EMPLOYEE_ID,2)的特定映射组合 目前,我正在使用以下查询来实现此目的: SELECT E.NAME AS `EMPLOYEE_NAME`, EXISTS( SELECT 1 FROM `EMPLOYEE_ROLE` WHERE (`EMPLOYEE_ROLE

我有一个表,用于维护
员工ID
到员工可以分配的一个或多个
角色ID
的映射。
ROLE\u ID
ROLE
表的主键

现在,我试图找出某个特定员工是否是团队领导(ROLE_ID=2)。也就是说,本质上,试图找出映射表中是否存在(EMPLOYEE_ID,2)的特定映射组合

目前,我正在使用以下查询来实现此目的:

SELECT E.NAME AS `EMPLOYEE_NAME`, 
 EXISTS( SELECT 1 FROM `EMPLOYEE_ROLE` WHERE 
   (`EMPLOYEE_ROLE`.`EMPLOYEE_ID` = `E`.`EMPLOYEE_ID`)
   AND (`EMPLOYEE_ROLE`.`ROLE_ID` = 2)) AS `IS_TEAM_LEADER`
 -- Assume some other column shall be selected from ER table, 
 -- hence necessitating the JOIN on ER
FROM EMPLOYEE E
JOIN EMPLOYEE_ROLE ER ON (ER.EMPLOYEE_ID = E.EMPLOYEE_ID)
GROUP BY E.EMPLOYEE_ID;
虽然这似乎完成了任务,但我正在寻找一种更有效的方法,因为当前形式的子查询似乎是多余的。不确定它是否相关,但可以使用
在\u集合中查找\u
或类似的功能吗

有谁能提出一个解决方案,因为我对性能最好的方法感兴趣

编辑1:我有意使用
JOIN EMPLOYEE_角色
,目的是从
ER
表中选择其他列。因此,我希望优化子查询,同时保持连接完整。因此,语句“当前形式的当前子查询似乎是多余的”


SQLFiddle:

使用exists子查询或使用join,但不应在一个查询中同时使用这两个子查询

我会使用join方法,因为在必要时很容易获得与角色相关的数据:

SELECT E.NAME AS `EMPLOYEE_NAME`, 
FROM EMPLOYEE E
INNER JOIN EMPLOYEE_ROLE ER ON (ER.EMPLOYEE_ID = E.EMPLOYEE_ID)
WHERE ER.ROLE_ID=2;
如果您需要一个包含所有员工的列表,其中有一个字段指示该员工是否为领导,请使用“左联接”而不是“内部联接”:

SELECT DISTINCT E.NAME AS `EMPLOYEE_NAME`, IF(ER.ROLE_ID IS NULL, 'NOT IS Leader','IS Leader') AS IsISLeader
FROM EMPLOYEE E
LEFT JOIN EMPLOYEE_ROLE ER ON ER.EMPLOYEE_ID = E.EMPLOYEE_ID AND ER.ROLE_ID=2;
“最佳表现”-


除此之外,请参见@Shadow的答案。

如果为不同的员工ID找到相同的名称,我会在SQL中包含员工ID,如果某些员工没有角色,也可以使用左联接:

SELECT E.EMPLOYEE_ID, E.NAME, SUM(IF(R.ROLE_ID=2,1,0)) IS_TEAM_LEADER
FROM EMPLOYEE E
LEFT JOIN EMPLOYEE_ROLE R ON E.EMPLOYEE_ID = R.EMPLOYEE_ID
GROUP BY 1,2

只需使用FK关系即可 将角色表创建为

table role{
RoleID
RoleName
Status
...}
并将employee表编辑为

table employee{
ID
name
...
}
创建表employeerole

table employeerole{
ID
roleID
employeeID
}

现在,您还可以使用规范化规则为每个员工管理多个角色

现在您可以使用查询了

SELECT employee.ID, employee.Name, employeerole.roleid FROM role 
INNER   JOIN employeerole ON role.RoleID = employeerole.roleid INNER
JOIN   dbo.employee ON dbo.employeerole.employeeid = dbo.employee.ID 
WHERE   employeerole.roleid = 2
表角色的ID为2,名称为,例如团队领导或经理


现在,此查询已完全优化,并将为您提供最佳结果

如果我理解正确,您将尝试获取所有员工及其所有角色,以及一个额外的列,指示他们是否是团队领导。如果是这样,您只需加入
EMPLOYEE\u角色
两次,第二次是
LEFT-join
以检查特定角色:

SELECT E.NAME, ER.ROLE_ID, ER2.EMPLOYEE_ID IS NOT NULL AS `IS_TEAM_LEADER`
  FROM EMPLOYEE E
  JOIN EMPLOYEE_ROLE ER ON ER.EMPLOYEE_ID = E.EMPLOYEE_ID
  LEFT JOIN EMPLOYEE_ROLE ER2 ON ER2.EMPLOYEE_ID = E.EMPLOYEE_ID AND ER2.ROLE_ID = 2;

SQL FIDLE:

以下是获取属于特定角色的所有员工的查询

SELECT e.NAME FROM EMPLOYEE e right join (SELECT EMPLOYEE_ID FROM
EMPLOYEE_ROLE WHERE ROLE_ID=2) er using(EMPLOYEE_ID);

假设一名员工不能两次担任领导,那么第二个查询中的这种区别可能是多余的。。不过,我想要一个唯一的on(员工id、角色id)来确保。此外,OP fiddle中的布尔值is_team_leader字段可以简单地定义为
ER。角色ID不为空,不包含所有IF内容。单个员工可能有多个角色,因此不同的。因为我们都不知道这家公司是如何运作的,也不知道作业中需要什么数据,所以我把重点放在这里。IF()用于格式化输出。是的,多行已被左联接过滤,将DISTINCT关闭的唯一问题是,如果一名员工可以两次被列为团队领导(很可能在规范中不允许这样做)。。因为这是一个性能问题,所以我要说得非常清楚。因此,如果OP遵循Rick James答案中的建议,则可以删除DISTINCT。。一个名为
IsISLeader
的列包含
“不是领导者”
“是领导者”
是可怕的。OP的提琴在一个名为
是团队领导者
的列中有一个简单的1或0,这要简单得多。为什么要添加可读性较低的语法将其复杂化?你是在认真地为一个名为
'IsISLeader'
的列辩护?这几乎表明这些是为Daesh工作的员工!查询结构和数据操作中的观点并非生来平等。。看看OP的小提琴,如果你故意改变这样的事情,你至少应该有一个合理的理由。员工可以有一个或多个角色。因此,在employee表中包含角色并不是理想的设计。它违反了规范化原则。请详细说明如何通过利用您提出的建议来提高给定查询的性能。我认为您的意思是
ROLE\u ID=2
,而不是
EMPLOYEE\u ID=2
SELECT e.NAME FROM EMPLOYEE e right join (SELECT EMPLOYEE_ID FROM
EMPLOYEE_ROLE WHERE ROLE_ID=2) er using(EMPLOYEE_ID);