每个部门的平均工资

时间:2017-08-02 14:41:46

标签: sql oracle

我正在做SQL简介,而我目前正在做这个练习,但我已经卡住了。

练习:

  

创建部门名称列表,该部门的经理ID,经理姓名(员工姓氏)以及每个部门的平均工资。

以下是练习的模式,只是我正在使用的表格。

CREATE TABLE  "EMPLOYEES"
("EMPLOYEE_ID" NUMBER(6,0),
"FIRST_NAME" VARCHAR2(20),
"LAST_NAME" VARCHAR2(25) CONSTRAINT "EMP_LAST_NAME_NN" NOT NULL ENABLE,
"EMAIL" VARCHAR2(25) CONSTRAINT "EMP_EMAIL_NN" NOT NULL ENABLE,
"PHONE_NUMBER" VARCHAR2(20),
"HIRE_DATE" DATE CONSTRAINT "EMP_HIRE_DATE_NN" NOT NULL ENABLE,
"JOB_ID" VARCHAR2(10) CONSTRAINT "EMP_JOB_NN" NOT NULL ENABLE,
"SALARY" NUMBER(8,2),
"COMMISSION_PCT" NUMBER(2,2),
"MANAGER_ID" NUMBER(6,0),
"DEPARTMENT_ID" NUMBER(4,0),
"BONUS" VARCHAR2(5),
 CONSTRAINT "EMP_SALARY_MIN" CHECK (salary > 0) ENABLE,
 CONSTRAINT "EMP_ID_PK" PRIMARY KEY ("EMPLOYEE_ID")
USING INDEX  ENABLE,
 CONSTRAINT "EMP_EMAIL_UK" UNIQUE ("EMAIL")
USING INDEX  ENABLE
);

CREATE TABLE  "DEPARTMENTS"
("DEPARTMENT_ID" NUMBER(4,0),
"DEPARTMENT_NAME" VARCHAR2(30) CONSTRAINT "DEPT_NAME_NN" NOT NULL ENABLE,
"MANAGER_ID" NUMBER(6,0),
"LOCATION_ID" NUMBER(4,0),
 CONSTRAINT "DEPT_ID_PK" PRIMARY KEY ("DEPARTMENT_ID")
USING INDEX  ENABLE
);

这就是我现在所拥有的,

select  d.department_name, d.manager_id,e.last_name as "manager_name" , 
avg(salary)
from departments d join employees e ON (e.employee_id=d.manager_id)
group by d.department_name,e.last_name, d.manager_id;

我能够生成它要求的所有字段,除了平均值,我确实通过单独的查询得到了答案

 select department_name, round(avg(salary)) from employees e join 
 departments d ON (e.department_id=d.department_id)
 group by department_name;

我无法弄清楚我的生活,如何做到这一点,以便给我平均工资的选择陈述有效,我试图HAVING条款不起作用,因为它限制了它的已经给了。希望有人可以向我解释我失踪了什么。感谢回复!

3 个答案:

答案 0 :(得分:2)

因为员工既可以引用经理和非管理人员,而且部门也有经理,您必须在同一个SQL中将employees表加入TWICE部门。你在同一个sql中寻找这两个连接:

此联接会将经理详细信息与部门关联:

departments inner join employees mgrs on departments.manager_id = mgrs.employee_id

此联接将员工与部门关联

departments inner join employees emps on emps.department_id = departments.department_id

所以,你的终极sql将在其中的某个地方:

FROM
 departments
 INNER JOIN employees mgrs ON ....
 INNER JOIN employees emps ON ....
WHERE

困惑?考虑另一个与您相关的示例。您有一个居住地址和工作地址。如果它是一个数据库,它可能会有表personsaddresses。它不会有personshome_addresseswork_addresses,因为家庭/工作地址只是一个地址。人员表可能包含home_address_idwork_address_id,每列中有不同的ID,指向地址中的2个不同的地址行。这意味着只有一次无法加入地址并获得您的工作和家庭住址。从逻辑上讲,它不起作用:如果只有一组地址列,它显示的是哪些数据 - 您的工作还是您的家?您不能在一个单元格中显示两个值,而不是..您必须添加更多单元格。我们在现有细胞块的右侧添加更多细胞...进行另一次加入!如果您希望在选择列表中包含以下列:

person.Name,
homeaddress.Street,
workaddress.Street

然后地址必须加入两次。

Person table
------------
Name      Home_Address_Id Work_Address_Id
JohnSmith 1               2

Address table
-------------
ID Building    Street
1  261         Great Hope Street
2  Office2000  Commercial Way

希望您也清楚地看到您的工作和家庭地址不同(您在城市工作,住在乡下,好吗?不允许家庭工作;)),所以您可以&# 39; t说:

person p INNER JOIN address a ON p.home_address_id = a.id AND p.work_address_id = a.id

因为当数据库将两个表连接在一起时,在它处理ON条件之前,它会将所有行连接到所有行(从概念上讲)然后过滤

Persons-Joined-To-Addresses
---------------------------
Name      Home_Address_Id Work_Address_Id ID Building    Street
JohnSmith 1               2               1  261         Great Hope Street
JohnSmith 1               2               2  Office2000  Commercial Way

您可以看到没有满足这两个条件的行,因为数据库扫描它生成的行,测试任何满足所有ON条件的行:

Does 1=1 and 2=1? No. Do not include the 'JohnSmith 1               2               1  261         Great Hope Street' row
Does 1=2 AND 2=2? No. Do not include the 'JohnSmith 1               2               2  Office2000  Commercial Way' row

如果您加入TWICE中的地址,那就完全不同了:

Persons-Joined-To-Addresses-Joined-To-Addresses-Again
-----------------------------------------------------
Name      Home_Address_Id Work_Address_Id IH BuildingH   StreetH           IW BuildingW   StreetW
JohnSmith 1               2               1  261         Great Hope Street 1  261         Great Hope Street
JohnSmith 1               2               1  261         Great Hope Street 2  Office2000  Commercial Way
JohnSmith 1               2               2  Office2000  Commercial Way    1  261         Great Hope Street
JohnSmith 1               2               2  Office2000  Commercial Way    2  Office2000  Commercial Way

在这4行中,只有一行满足连接的条件。这是数据库测试的列表:

Does 1=1 and 2=1? No. Don't include the 'JohnSmith/Great Hope Street/Great Hope Street' row
Does 1=1 and 2=2? YES. Include the 'JohnSmith/Great Hope Street/Commercial Way' row
Does 1=2 AND 2=1? No. Do not include the 'JohnSmith/Commercial Way/Great Hope Street' row
Does 1=2 AND 2=2? No. Do not include the 'JohnSmith/Commercial Way/Commercial Way' row

这两个条件与以前相同,但我已将ID列重命名为IH和IW。条件是home_address_id = IH and work_address_id = IW。你掌握“a = b和x = y?' a a = b AND x = y?'中的概念非常重要。上面的行你欣赏我们通过附加" home"的含义来区别对待地址ID。或者"工作"给他们。说:

  

是否。主页 _address_id = id_from_addresses_ aliased_as_home 和人。工作 _address_id = id_from_addresses_ aliased_as_work

将这个结合到一个sql之后,总结员工的工资就可以了。在每个联接中,使用不同的雇员表别名为雇员表。我打电话给我的mgrs和emps所以我知道数据是否是"经理级别"或"员工级别"

我还没有为您编写整个查询,因为这显然是一项功课,但如果您需要更多帮助,请发表评论:)

答案 1 :(得分:0)

这就是你想要的吗?

select d.department_name, d.manager_id,e.last_name as "manager_name", avg(salary)
from departments d join employees e ON (e.employee_id=d.manager_id)
group by d.department_name,d.manager_id, e.last_name ;

答案 2 :(得分:0)

WITH DINFO AS (SELECT departments.department_name,departments.department_id,departments.manager_id,ROUND(AVG(salary)) AS AVGSAL
FROM departments
INNER JOIN employees ON (employees.department_id = departments.department_id)
GROUP BY departments.department_name,departments.department_id,departments.manager_id
)

SELECT DINFO.department_name,DINFO.manager_id,last_name, DINFO.AVGSAL FROM employees e, DINFO
WHERE e.employee_id = DINFO.manager_id;