免责声明:我是开发人员而非DBA。
我一直是Oracle中USING子句的忠实粉丝,因为我不小心偶然发现它并且用它代替了老式的ON子句,从那时起就将事实表与维度表连接起来。对我来说,它创建了一个更简洁的SQL,并生成了更简洁的结果集,没有不必要的重复列。
然而,昨天我被一位同事要求将我的所有USING条款转换为ON。我会和他核实一下,问他原因是什么。他与数据库的工作比我更密切,所以我认为他有一些很好的理由。
我没有收到他的回复(我们在不同的时区工作),但我想知道是否有关于使用“使用”条款的指导方针或最佳做法?我已经搜索了很多,但没有找到任何确定的东西。事实上,我甚至都没有在任何地方进行过很好的辩论。
有人可以对此有所了解吗?或者提供关于该主题的良好讨论的链接?
谢谢!
答案 0 :(得分:24)
你可能已经意识到这种区别,但是来自the documentation:
ON 条件 使用
ON
子句指定连接条件。这样做 允许您指定与任何搜索或过滤器分开的连接条件WHERE
子句中的条件。使用(列)当您指定列的等值连接时
USING column
子句表示在两个表中具有相同的名称 要使用的列。只有在连接时才能使用此子句 两个表中的列具有相同的名称。在这个条款中,不要 使用表名或表别名限定列名。
所以这些是等价的:
select e.ename, d.dname
from emp e join dept d using (deptno);
select e.ename, d.dname
from emp e join dept d on d.deptno = e.deptno;
在很大程度上,您使用的是风格问题,但有(至少)两种情况您无法使用using
:( a)当列名不相同时两个表,以及(b)当您想要使用连接列时:
select e.ename, d.dname, d.deptno
from emp e join dept d using(deptno);
select e.ename, d.dname, d.deptno
*
ERROR at line 1:
ORA-25154: column part of USING clause cannot have qualifier
当然,只要你没有另一个没有使用它连接的相同列的表,你就可以放弃限定符和select ..., deptno
:
select e.ename, d.dname, deptno
from emp e join dept d using (deptno) join mytab m using (empno);
select e.ename, d.dname, deptno
*
ERROR at line 1:
ORA-00918: column ambiguously defined
在这种情况下,您只能 选择合格的m.deptno
。 (好吧,这是相当人为的......)。
我可以看到避免using
的主要原因只是一致性;因为你有时候不能使用它,偶尔切换到on
这些情况可能会有点刺耳。但同样,这更多是关于风格而不是任何深层次的技术原因。
也许你的同事只是强加(或建议)编码标准,但只有他们知道这一点。如果要求您更改一些正在审核的新代码或旧代码,也不是很清楚。如果是后者,那么不管他们更喜欢on
的原因,我认为你需要单独证明修改经过验证的代码,因为即使重新测试修改后的代码,也存在引入新问题的风险 - 除了返工和重新测试所涉及的成本/精力之外。
但有几件事让我对你的问题感到震惊。首先,您将on
语法描述为“老式”,但我认为这不公平 - 两者都是有效且最新的(截至SQL:2011我认为,但引用需要!)。这个:
生成更简洁的结果集,没有不必要的重复列。
...我认为你建议你使用select *
,否则你只需选择其中一个值,尽管有一些额外的字符用于限定符。除了即席查询和一些子查询之外,使用select *
通常被认为是不好的做法(例如here)。
答案 1 :(得分:2)
似乎主要区别在于语法:列在USING
连接中合并。
在所有情况下,这意味着您无法从特定表中访问已连接列的值,实际上某些SQL将无法编译,例如:
SQL> WITH t AS (SELECT 1 a, 2 b, 3 c FROM dual),
2 v AS (SELECT 1 a, 2 b, 3 c FROM dual)
3 SELECT t.* FROM t JOIN v USING (a);
SELECT t.* FROM t JOIN v USING (a)
^
ORA-25154: column part of USING clause cannot have qualifier
在外连接中,这意味着您无法访问外部表值:
SQL> WITH t AS (SELECT 1 a, 2 b, 3 c FROM dual),
2 v AS (SELECT NULL a, 2 b, 3 c FROM dual)
3 SELECT * FROM t LEFT JOIN v USING (a)
4 WHERE v.a IS NULL;
WHERE v.a IS NULL
^
ORA-25154: column part of USING clause cannot have qualifier
这意味着这种反连接语法与USING
子句没有等价物:
SQL> WITH t AS (SELECT 1 a, 2 b, 3 c FROM dual),
2 v AS (SELECT NULL a, 2 b, 3 c FROM dual)
3 SELECT * FROM t LEFT JOIN v ON v.a = t.a
4 WHERE v.a IS NULL;
A B C A B C
---------- ---------- ---------- - ---------- ----------
1 2 3
除此之外,一旦SQL有效,我不知道有任何区别。
但是,由于这种语法似乎不太常用,如果存在仅影响USING
子句的特定错误,我不会感到惊讶,特别是在引入ANSI SQL的早期版本中。我没有在MOS上找到任何可以证实这一点的东西,部分原因是 USING 这个词在bug描述中无处不在。
如果不使用此功能的原因是由于错误,我认为证据的负担在于您的同事:必须引用/记录错误,以便一旦错误发生,最终可以解除禁令修补(数据库升级...)。
如果原因是装饰性的或编码约定的一部分,当然也必须记录它。
答案 2 :(得分:0)
使用US还你不能像以下那样进行连接: 选择a.id,aval,bval,cval 来自a 在a.id = b.id上左连接b 在c.id = b.id;
上左连接c也就是说,只有当它与B表中的一行匹配时,才从C中给出该列。