因此,我正在学习有关从多个表中获取数据的知识,并且我对NATURAL JOIN和USING子句有疑问。所以我有2个表要从中提取数据;员工和部门。
SQL> describe employees
Name Null? Type
----------------------------------------- -------- ------------------------
EMPLOYEE_ID NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
EMAIL NOT NULL VARCHAR2(25)
PHONE_NUMBER VARCHAR2(20)
HIRE_DATE NOT NULL DATE
JOB_ID NOT NULL VARCHAR2(10)
SALARY NUMBER(8,2)
COMMISSION_PCT NUMBER(2,2)
MANAGER_ID NUMBER(6)
DEPARTMENT_ID NUMBER(4)
SQL> describe departments
Name Null? Type
----------------------------------------- -------- ------------------------
DEPARTMENT_ID NOT NULL NUMBER(4)
DEPARTMENT_NAME VARCHAR2(30)
MANAGER_ID NUMBER(6)
LOCATION_ID NUMBER(4)
当我在两个不同的表达式中使用NATURAL JOIN和USING时,我有两个不同的输出。我知道USING专门匹配两个表中的一列,但是这如何影响输出?与NATURAL JOIN相比,使用USING的表达式如何产生一个额外的值?
SELECT department_id, manager_id, last_name, location_id
FROM employees NATURAL JOIN departments
WHERE department_id = 80
ORDER BY location_id desc;
DEPARTMENT_ID MANAGER_ID LAST_NAME LOCATION_ID
------------- ---------- ------------------------- -----------
80 149 Abel 2500
80 149 Grant 2500
80 149 Taylor 2500
SELECT department_id, departments.manager_id, last_name, location_id
FROM employees JOIN departments
USING (department_id)
WHERE department_id = 80
ORDER BY location_id desc;
DEPARTMENT_ID MANAGER_ID LAST_NAME LOCATION_ID
------------- ---------- ------------------------- -----------
80 149 Zlotkey 2500 <-Additional Line*
80 149 Grant 2500
80 149 Taylor 2500
80 149 Abel 2500
感谢您的帮助和建议!
答案 0 :(得分:5)
由于NATURAL JOIN在所有具有相同名称的列上联接,因此您的NJ查询也将在manager_id上联接,而USING表单则不会联接
如果您查看USING表单,您会发现每个表中的manager_id是不同的。 (进行查询SELECT *
,您会看到。。
当自然加入时,两个表之间的manager_id差异将从结果中删除该行
值得注意的是,自然连接和使用应该很少使用。可以肯定地了解它们,以便欣赏它们的存在,但是出于一致和明确的行为,您应该坚持使用常规的显式联接-如果将来要升级应用程序,并且在这两个表中添加了两个新列,它们的名称相同但是NJ将使用不同的数据失败。
编辑:
运行此:
SELECT *
FROM employees JOIN departments
USING (department_id)
WHERE department_id = 80
ORDER BY location_id desc;
查看显示管理员ID的两列。 Zlotkey行上的数据将不同
您自然加入即可有效地做到这一点:
SELECT *
FROM employees e JOIN departments d
on e.department_id = d.department_id AND e.manager_id = d.manager_id
WHERE department_id = 80
ORDER BY location_id desc;
并且on e.department_id = d.department_id AND e.manager_id = d.manager_id
对于zlotkey行不是正确的
这就是为什么自然连接有风险并且可能无用的原因-仅因为两列具有相同的名称并不意味着它们中的数据是相关的。实际上,在您的情况下,您的部门有经理,而员工有经理。我的工作中也有此设置,但是作为我的经理的那个人不是我所在部门的经理
答案 1 :(得分:-1)
我的第一条建议是对您的架构应用“单一责任”原则。考虑谁将更新数据的角色/角色,以及他们将在何种情况下进行更新。底线:employees
表的职责过多。雇员姓名和雇用日期通常不如工资变动那么频繁。工资将在每个发薪日获得。电话号码可能是私人的。考虑通过根据职责划分employees
表来创建新表。
第二,考虑区分(a)为员工等“实体”建模的表与(b)为这些实体之间的关系建模的表。您的两个表当前混合了这两个概念。考虑一个用于组织字符关系(由谁管理)的新表,以及一个用于模拟员工与部门之间关系的表。
第三,考虑一下您是否在整个架构中为相同的数据元素赋予相同的名称,例如可能“员工经理”和“部门经理”的含义不同(例如,在涉及两者的查询中,您发现您必须重命名至少一个以避免混淆)。如果是这样,请考虑使名称更明确,不要回答要在上下文中提供的表名。
根据上述建议重新设计架构后,您可能会发现查询工作正常。 TL; DR,如果您发现很难编写简单的SQL DML,请考虑修改SQL DDL。