Oracle USING子句的最佳实践

时间:2013-04-23 06:58:22

标签: oracle join using natural-join

免责声明:我是开发人员而非DBA。

我一直是Oracle中USING子句的忠实粉丝,因为我不小心偶然发现它并且用它代替了老式的ON子句,从那时起就将事实表与维度表连接起来。对我来说,它创建了一个更简洁的SQL,并生成了更简洁的结果集,没有不必要的重复列。

然而,昨天我被一位同事要求将我的所有USING条款转换为ON。我会和他核实一下,问他原因是什么。他与数据库的工作比我更密切,所以我认为他有一些很好的理由。

我没有收到他的回复(我们在不同的时区工作),但我想知道是否有关于使用“使用”条款的指导方针或最佳做法?我已经搜索了很多,但没有找到任何确定的东西。事实上,我甚至都没有在任何地方进行过很好的辩论。

有人可以对此有所了解吗?或者提供关于该主题的良好讨论的链接?

谢谢!

3 个答案:

答案 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)

Related question

似乎主要区别在于语法:列在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中给出该列。