【问题标题】:How to simplify nested select in where clause?如何简化 where 子句中的嵌套选择?
【发布时间】:2017-03-09 19:22:03
【问题描述】:

我有 4 张桌子 EMPLOYEECOMPANYWORKSMANAGES。这些表定义如下-

CREATE TABLE EMPLOYEE
(
    EMPLOYEE_NAME VARCHAR2(50) NOT NULL PRIMARY KEY,
    STREET VARCHAR2(50) NOT NULL,
    CITY VARCHAR2(30) NOT NULL
);

CREATE TABLE COMPANY
(
    COMPANY_NAME VARCHAR2(100) NOT NULL PRIMARY KEY,
    CITY VARCHAR2(50) NOT NULL
);

CREATE TABLE WORKS
(
    EMPLOYEE_NAME VARCHAR2(50) NOT NULL PRIMARY KEY REFERENCES EMPLOYEE(EMPLOYEE_NAME),
    COMPANY_NAME VARCHAR2(100) NOT NULL REFERENCES COMPANY(COMPANY_NAME),
    SALARY NUMBER(12,2) NOT NULL
);

CREATE TABLE MANAGES
(
    EMPLOYEE_NAME VARCHAR2(50) NOT NULL PRIMARY KEY REFERENCES EMPLOYEE(EMPLOYEE_NAME),
    MANAGER_NAME VARCHAR2(50) NOT NULL
);

我需要找到与他们工作的公司居住在同一城市的所有员工。到目前为止,我已经做到了。

SELECT EMPLOYEE_NAME AS Names
FROM EMPLOYEE
WHERE CITY = (
    SELECT CITY
    FROM COMPANY
    WHERE COMPANY_NAME = (
        SELECT COMPANY_NAME
        FROM WORKS
        WHERE WORKS.EMPLOYEE_NAME = EMPLOYEE.EMPLOYEE_NAME
    )
);

一切正常。但我想知道有没有更简单的方法来做这个查询?

【问题讨论】:

  • 了解什么是 INNER JOIN,您可以将其简化为大约一行 SQL。您还应该重新考虑您的专栏。如果您有两名名为“John Smith”的员工或一家在同一个城市有两个办事处的公司会怎样?
  • @KenWhite 感谢您的建议。我想我应该改变主键。
  • 我认为你应该在 EMPLOYEE 和 COMPANY 中添加 ID 列,然后你的 WORKS 表将是 EMPLOYEE_ID、COMPANY_ID,而你的 MANAGES 表将变为 EMPLOYEE_ID、MANAGER_ID,其中 manager_id 是 EMPLOYEE_ID(工人可以'不是由非员工管理的,对吗?)。
  • @KenWhite 是的,你是对的。每个经理都是员工。

标签: sql database oracle oracle11g


【解决方案1】:

您可以使用显式内连接代替嵌套子选择

SELECT EMPLOYEE.EMPLOYEE_NAME AS Names
FROM EMPLOYEE
INNER JOIN WORKS ON  WORKS.EMPLOYEE_NAME = EMPLOYEE.EMPLOYEE_NAME
INNER JOIN COMPANY ON  EMPLOYEE.CITY = COMPANY.CITY

【讨论】:

  • 它给出了一个错误 - 00918. 00000 - "column ambiguously defined"
  • 答案已更新为员工的显式表名
  • @MD.KhairulBasar . 只是一个建议.. 与您的问题相关的几个正确答案已发布.. 您应该选择其中一个并将其标记为已接受..
  • 我接受了你的回答。这是最简单的一种。但是,当我编写查询时,EMPLOYEE 带有下划线并显示EMPLOYEE is disconnected from the rest of the join graph,尽管该语句正在运行并且运行良好。你能告诉我为什么加下划线吗??
  • 您使用的是哪个 IDE .. ?
【解决方案2】:
SELECT EMPLOYEE.EMPLOYEE_NAME As Names
FROM EMPLOYEE
INNER JOIN WORKS ON WORKS.EMPLOYEE_NAME = EMPLOYEE.EMPLOYEE_NAME
INNER JOIN COMPANY ON COMPANY.COMPANY_NAME = WORKS.COMPANY_NAME
WHERE COMPANY.CITY = EMPLOYEE.CITY

这基本上就是 Ken White 建议使用内连接的方法。

【讨论】:

  • 你能解释一下为什么SELECT EMPLOYEE_NAME 给出错误 - "column ambiguously defined"SELECT EMPLOYEE.EMPLOYEE_NAME 效果很好??
  • EMPLOYEE_NAME 存在于两个表中,EMPLOYEE 和 WORKS,所以当你只是说你想要 EMPLOYEE_NAME 字段时,SQL 并不知道你想从哪个表中获取数据。这就是为什么它是模棱两可的。所以只需要在SELECT语句中指定表名和字段名即可。
【解决方案3】:

你提到了WHERE 子句,所以你可以这样做:

SELECT e.EMPLOYEE_NAME As Names
FROM EMPLOYEE e
WHERE e.CITY = (SELECT c.CITY
                FROM Company c JOIN
                     Works w
                     ON c.COMPANY_NAME = w.COMPANY_NAME
                WHERE w.EMPLOYEE_NAME = e.EMPLOYEE_NAME
               );

注意事项:

  • 这假设员工只为一家公司工作。否则,子查询可能会返回多行。您可以通过将= 更改为IN 来处理这种情况。
  • 名称是用于外键关系的一个非常糟糕的键。通常数字ID更好。如果员工或公司更改姓名会怎样?
  • 表别名使查询更易于编写和阅读。

【讨论】:

  • 它工作正常。谢谢你。但我想知道一件事。下面 Sid 给出了一个答案,从多个表中选择列并检查 where 子句中的条件。这看起来更简单。那么,使用 INNER JOIN 或两者都使用有什么好处吗?
  • Sid 的答案使用古老的语法来连接已经过时了大约 2 年的连接。在 SQL 中编写 JOIN 的正确方法是使用显式的 JOIN 语法和 ON 子句。如果您想使用这种方法,那么 user3498540 的解决方案是正确的方法。
  • 好的。非常感谢。 :D
【解决方案4】:
    select employee.employee_name 

    from company, employee, works 

    where company.company_name=works.company_name 

      and works.employee_name=employee.employee_name 
      and employee.city = company.city

【讨论】:

  • 呃。 WHERE 子句连接是邪恶的。 :-)
  • 虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-08
  • 2021-07-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多