为啥此相关子查询在 Oracle 和 SQL Server 中的工作方式不同

Posted

技术标签:

【中文标题】为啥此相关子查询在 Oracle 和 SQL Server 中的工作方式不同【英文标题】:Why this correlated subquery works differently in Oracle and SQL Server为什么此相关子查询在 Oracle 和 SQL Server 中的工作方式不同 【发布时间】:2019-12-07 23:41:14 【问题描述】:

我有表 EMPLOYEES,其中包含employee_id、department_id、salary 列(标准 HR 模式)。

为什么要查询:

SELECT 
    employee_id,
    department_id,
    salary,
    (
        select min(EMPLOYEES.salary) 
        from HR.EMPLOYEES E 
        where department_id = EMPLOYEES.department_id
    )
from HR.EMPLOYEES;

在 Oracle 中执行但在 SQL Server 中返回错误?

【问题讨论】:

您能否通过“在 Oracle 中工作但在 SQL Server 中不工作”的意思给我们一个提示? 我的错误:“在 Oracle 中执行,但在 SQL Server 中返回错误”更加精确。但我已经收到了答案。 好的,一个更具描述性的帖子将有助于包含实际的错误消息。这很容易,但将来问题可能不会那么明显。欢迎来到 SO! 【参考方案1】:

SQL Server 不允许在相关子查询的聚合中引用外部查询。这通常很好,因为这样的结构通常不是很有用。我很确定错误消息是这样说的。

我认为这是您真正想要的查询:

select e.employee_id, e.department_id, e.salary,
       (select min(e2.salary)
        from HR.EMPLOYEES E2
        where e2.department_id = e.department_id
       )
from HR.EMPLOYEES e;

建议您限定所有列引用,尤其是在相关子查询中。

您的版本将只返回外部查询中每个员工的薪水。您不需要相关的子查询来执行此操作。

【讨论】:

“SQL Server 不允许在相关子查询的聚合中引用外部查询。”你回答了我的问题。错误消息正是如此。当然,我不需要相关的子查询来做到这一点,我只是很惊讶为什么 Oracle 和 SQL Server 之间存在差异......【参考方案2】:

您需要在子查询中限定department_id 列,否则它所引用的表是不明确的。某些 RDBMS 可能允许使用您的语法,但我不确定这是否会产生正确的结果。

为子查询返回的值提供别名也是一个好主意。

因此:

select
    employee_id,
    department_id,
    salary,
    (
        select min(e1.salary) 
        from hr.employees e1 
        where e1.department_id = e.department_id
    ) min_department_salary
from hr.employees e;

另外,请注意,您可以通过使用窗口函数(Oracle 和 SQLServer 已经支持很长时间)在不使用子查询的情况下获得相同的结果:

select
    employee_id,
    department_id,
    salary,
    min(salary) over(partition by department_id) min_department_salary
from hr.employees e;

【讨论】:

以上是关于为啥此相关子查询在 Oracle 和 SQL Server 中的工作方式不同的主要内容,如果未能解决你的问题,请参考以下文章

将 TOP 1 相关子查询从 SQL Server 翻译到 Oracle

SQL中,多表连接查询和不相关子查询从查询效率上来说,哪种查询的效果更好?为啥 ?

Oracle SQL - 多级相关子查询不起作用

求SQL相关子查询和嵌套子查询通俗的区别 ?

Oracle SQL如何优化IN不相关子查询

为啥 SQL 子查询中的外部引用会产生不同的结果?