2012-07-25 53 views
0

员工可以在很多部门工作,而且每个部门可以有很多员工。因此需要一个关系表关系表上的SQL查询

表:
EMP(EID,为ename,EAGE,esalary)
工程(EID,确实,pct_time)
部门(确实,DNAME,预算,经理ID)

找到所有在这两种软件工作的员工和硬件:

SELECT e.ename FROM EMP e, Works w, Dept d 
WHERE e.eid = w.eid AND w.did = d.did AND d.did = 
(SELECT did FROM dept WHERE dname = 'Hardware' OR 'Software') 

按乔恩:

SELECT e.ename FROM EMP e OR Works w OR Dept d 
WHERE e.eid = w.eid AND w.did = d.did AND d.did = 
(SELECT did FROM dept WHERE dname = 'Hardware' OR 'Software') 

而我只是不知道如何确保在同一个eid下的硬件和软件的Works中有两个条目。

+0

您的'从雇主或工作部门或者部门'语法是标准SQL符号上的一项创新。我担心你正在使用的DBMS可能会对语法采取异常并拒绝你的SQL语句。 – 2012-07-25 03:34:22

回答

1
select e.name 
    from emp e, works h_w, dept h_d, works s_w, dept s_d 
where e.eid = h_w.eid 
    and e.eid = s_w.eid 
    and h_w.did = h_d.did 
    and h_d.dname = 'Hardware' 
    and s_w.did = s_d.did 
    and s_d.dname = 'Software' 
+0

哇,这是伟大的信息,我不知道你可以用不同的名字别名相同的表。 – KevinCameron1337 2012-07-25 03:07:35

+0

通常,您应该在FROM子句中使用'现代'(意思是1992年后)的SQL标准JOIN表示法,而不是'古代'(意思是1992年以前)以逗号分隔的表名列表。 – 2012-07-25 03:23:40

+0

像我在编辑中所做的那样? – KevinCameron1337 2012-07-25 03:32:19

1

这里是你如何解决这个问题的步骤:

  • 首先,获取的所有行works表所在的部门是无论是硬件或软件
  • 然后对于任何员工来说,如果存在两行,这意味着他/她在两个部门工作。
  • 对于任何员工,如果少于两行的存在,这意味着他/她只能为两者中的一员工作,或者根本不工作。
  • 我们需要检索具有两行的员工。

所以我们可以首先要做的就是从works表中选择,加入其对dept表,并筛选出不属于硬件或软件的任何部门:

SELECT a.* 
FROM works a 
INNER JOIN dept b ON a.did = b.did 
WHERE b.dname IN ('Hardware','Software') 

那么,想什么do是由每个员工分组的,这将使我们能够访问聚合信息,例如每位员工的行数或sum/max/min/avg /等。其他栏目。我们必须以计数的工作:

SELECT a.eid 
FROM works a 
INNER JOIN dept b ON a.did = b.did 
WHERE b.dname IN ('Hardware','Software') 
GROUP BY a.eid 
HAVING COUNT(1) = 2 

这给了我们只有eid S作正是两行(即适用于软件和硬件部门)。

eids是不够的。我们希望有关员工的整个信息,所以我们必须换行整个查询,并加入其对员工表来获取其信息的休息:

SELECT a.* 
FROM emp a 
INNER JOIN 
(
    SELECT a.eid 
    FROM works a 
    INNER JOIN dept b ON a.did = b.did 
    WHERE b.dname IN ('Hardware','Software') 
    GROUP BY a.eid 
    HAVING COUNT(1) = 2 
) b ON a.eid = b.eid 

有你有它:员工谁工作在软件和硬件部门。您可以单独执行上面的每个查询,查看我们如何到达最终解决方案的中间步骤。

+0

现在很清楚,我明白了,但我不认为我会自己想出来。虽然,当我通过这个进展时,我可能需要其中一些技术来解决其他问题。非常感谢。 – KevinCameron1337 2012-07-25 03:20:38

1

下面是查询的另一种表述:

SELECT e.* 
    FROM emp AS e 
    JOIN (SELECT w.eid 
      FROM works AS w JOIN dept AS d 
      ON d.did = w.did AND d.dname = 'Software') AS s 
    ON s.eid = e.eid 
    JOIN (SELECT w.eid 
      FROM works AS w JOIN dept AS d 
      ON d.did = w.did AND d.dname = 'Hardware') AS h 
    ON h.eid = e.eid 

这有两个对称的子查询,一个生成的软件部门的员工ID,为硬件部门的一个发电员工ID。选定的员工是那些在两个部门都列有ID的人(因为他们都是内部连接)。

+0

别名s和h给你处理SELECT查询的结果吗?我发现这是最难遵循的一个。 – KevinCameron1337 2012-07-25 03:37:12

+0

'AS s'有效地将查询的结果命名为's'(就像它是一个表或视图一样),同样用'AS h'和它的查询命名。如果你没有学过JOIN注释,那么这可能会更困难,但(IMNSHO)在学校没有教你加入注释。有很多原因为什么他们比旧式标记更好。 – 2012-07-25 03:48:20