【问题标题】:Oracle show all employees with greater than average salary of their departmentOracle 显示所有员工的工资高于其部门的平均工资
【发布时间】:2011-04-28 21:21:49
【问题描述】:

我正在编写查询以查找收入高于其部门平均工资的员工。我需要显示该部门的员工 ID、工资、部门 ID 和平均工资。

我有一个几乎可以正常工作的查询,但它一直给我“ORA-00904:“AVG_SAL”:无效标识符”错误。我这样做是否正确。为什么我会收到此无效标识符错误?

SELECT employee_id, salary, department_id,
  (SELECT ROUND(AVG(salary),2)
  FROM employees e_inner
  WHERE e_inner.department_id = e.department_id) AS avg_sal
FROM employees e
WHERE salary > avg_sal
ORDER BY avg_sal DESC

【问题讨论】:

    标签: sql oracle plsql ora-00904


    【解决方案1】:

    更有效地使用分析:

    select employee_id, salary, department_id, avg_sal
    from
    (
      SELECT employee_id, salary, department_id, 
        round(avg(salary) over (partition by department_id), 2) avg_sal
      from emp
    )
    where salary > avg_sal
    order by avg_sal desc
    

    【讨论】:

    • +1 好主意。您可以通过 1) 每行前四个空格来格式化; 2)选择代码并按CTRL-K;或3)选择代码并单击代码按钮,标签为1010101的那个
    • +1 OP 可能一直希望特别了解“在 WHERE 子句中引用列别名”问题,但这种技术值得强调。
    • +1,分析是非常强大的构造,根据我的经验,比使用自联接等的等效 SQL 更有效。
    【解决方案2】:

    我不相信您可以在 WHERE 子句中引用列别名(在本例中为 avg_sal)。

    您需要重复该内部查询,即:

    SELECT employee_id, salary, department_id,
      (SELECT ROUND(AVG(salary),2)
      FROM employees e_inner
      WHERE e_inner.department_id = e.department_id) AS avg_sal
    FROM employees e
    WHERE salary > 
     (SELECT ROUND(AVG(salary),2)
      FROM employees e_inner
      WHERE e_inner.department_id = e.department_id)
    ORDER BY avg_sal DESC
    

    这两个内部查询不太好,但这是纠正错误的最直接的方法。

    更新:尚未对此进行测试,但请尝试以下操作:

    SELECT e.employee_id, e.salary, e.department_id, b.avg_sal
    FROM employees e
    INNER JOIN
    (SELECT department_id, ROUND(AVG(salary),2) AS avg_sal
     FROM employees
     GROUP BY department_id) e_avg ON e.department_id = e_avg.department_id AND e.salary > e_avg.avg_sal
    ORDER BY e_avg.avg_sal DESC
    

    【讨论】:

    • +1:正确 - 在 WHERE 子句中不能引用列别名。在 Oracle 中,最早可以引用它们的是 ORDER BY。
    • 我担心我将不得不暴力破解并执行两个子查询。知道为什么我不能引用这样的列别名吗?
    • 为什么不使用 avg(salary) over (partition by department) 如下所示? (我不知道为什么格式显示不好。)
    • @ChrisOPeterson SQL 查询的概念模型是这样向我解释的:尽管 SELECT 子句在 WHERE 子句之前在语法上,但 WHERE 子句实际上是在执行 首先。稍加思考就会告诉我们原因:首先检索结果集(FROM/JOIN),然后过滤(WHERE),最后从(SELECT)中选择。因此,这样的别名仅适用于 WHERE 评估后的结果列。
    • 我喜欢你的回答 RussellH,但它比我现在更先进一点。我真的很想知道列别名是如何工作的,因为它们让我在 oracle 中发疯。我写的查询对我来说非常有意义,但不起作用。我想知道为什么。
    【解决方案3】:

    你可以将它重写为一个连接:

    SELECT  e1.employee_id
    ,       e1.salary
    ,       e1.department_id
    ,       ROUND(AVG(e2.salary),2) as Avg_Sal
    FROM    employees e
    JOIN    employees e2
    ON      e2.department_id = e.department_id
    GROUP BY
            e1.employee_id
    ,       e1.salary
    ,       e1.department_id
    HAVING  e1.salary > ROUND(AVG(e2.salary),2)
    

    或子查询:

    SELECT  *  
    FROM    (
            SELECT  employee_id
            ,       salary
            ,       department_id
            ,       (
                    SELECT  ROUND(AVG(salary),2)
                    FROM    employees e_inner
                    WHERE   e_inner.department_id = e.department_id
                    ) AS avg_sal
            FROM    employees e
            ) as SubqueryAlias
    WHERE   salary > avg_sal
    

    【讨论】:

    • 我不明白为什么需要自我加入。为什么不使用 round(avg(salary) over (partition by department_id), 2) avg_sal?
    • @RussellH:子查询是对数据的第二次传递,因此除非执行计划中有出色的内容,否则您的观点没有实际意义。
    • @OMG Ponies,在 Oracle 11G R2 中,这两个查询都对员工进行了 2 次扫描,而在我测试它们时,带有窗口函数的查询只进行了一次扫描。
    • @Quandary -- 第二个只是嵌套在第二个查询中的 OP 查询,因此列别名可以在谓词中使用。它的性能不太可能比接受的答案差,后者会多次重复子查询。但总体而言,分析答案可能具有最佳性能。
    • @Dave Costa:我不能代表 Oracle,但在 MS-SQL 上,从子选择中选择将为子选择创建一个临时表,这意味着如果子选择表包含数千行,它会变得非常非常慢,因为它必须交换临时表,因为没有足够的 RAM。永远不要这样做,否则您会在生产环境中遇到性能和/或超时问题。
    【解决方案4】:
    select *
    from employees e
    join(
          select Round(avg(salary)) AvgSal,department_id,department_name as dept_name
          from employees join departments 
          using (department_id)
          group by department_id,department_name
    ) dd
    using(department_id)
    where e.salary > dd.AvgSal;
    

    另一种解决方案

    select * 
    from employees e, 
    (
     select 
        department_id, 
        avg(salary) avg_sal 
     from employees 
     group by department_id
    ) e1
    where e.department_id=e1.department_id 
    and e.salary > e1.avg_sal
    

    【讨论】:

    • 您的答案需要格式化,以便发帖人能够理解。
    猜你喜欢
    • 2019-01-25
    • 2020-08-09
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 2016-07-07
    • 2018-04-16
    • 2012-08-02
    • 1970-01-01
    相关资源
    最近更新 更多