PostgreSQL 多个 USING 子句

4

我经常使用(开玩笑的意思)在PostgreSQL中使用USING语句,并且想知道在同一键名上有多个USING的情况下,如何做出选择。

让我们用一个简单的例子来解释: 假设有表A、B和C,它们都有userid列。 如果我执行以下操作:

SELECT A.c1, A.c2, ...
FROM A
JOIN B USING(userid)
JOIN C USING(userid) ;

PostgreSQL如何处理表B和C都有列userid的冲突?结果输出是什么?
A.userid = B.userid AND A.userid = C.userid

或者
A.userid = B.userid AND B.userid = C.userid 

希望我的表述足够清晰,感谢您提前的回答。

附:我不使用多个USING子句,因为我认为这样不易读,但我想知道它是如何工作的。


“JOIN C USING(userid)” 使用了前一个连接中唯一的 userid,既不是 A 的也不是 B 的。 - jarlh
您的问题涉及查询处理顺序。如所示,解释计划将显示当前系统上使用您的数据量的过程。但是,该顺序并非固定不变。优化器根据可用索引、表大小、当前统计信息等选择操作顺序。随着这些因素的变化,计划本身也可能会发生变化。 - Belayer
3个回答

2
如果您使用了USING,则在连接结果中只会有一个userid,因此不会产生歧义。
所有的文档所说的是

此外,JOIN USING的输出会抑制冗余列:

但它还涉及到列引用。您可以使用未经表格确认的userid,而不会出现“模糊的列引用”错误,因为PostgreSQL知道该列仅存在一次。

只要这些连接是 Inner Join,那就没问题了,但如果这些连接是 Outer Joins 呢?至少语法允许这样做。 - dnoeth
然后您就会得到非空值。 - Laurenz Albe
谢谢。很有道理,我刚刚查看了SQL标准,结果实际上是使用COALESCE定义的。 - dnoeth

2

使用内连接,该查询语句为:

SELECT A.c1, A.c2, ...
FROM A JOIN
     B
     USING (userid) JOIN
     C
     USING (userid) ;

等同于:

SELECT A.c1, A.c2, ...
FROM A JOIN
     B
     ON B.userid = A.userid JOIN
     C
     ON C.userid = A.userid ;  -- or "C.userid = B.userid", it doesn't matter

请注意,在内连接中,NULL值会导致比较失败,因此它们不会成为结果集中的问题。
对于左外连接,逻辑与上述相同。对于全外连接:
SELECT A.c1, A.c2, ...
FROM A FULL JOIN
     B
     ON B.userid = A.userid FULL JOIN
     C
     ON C.userid = COALESCE(A.userid, B.userid) ;  

请注意,在查询的其余部分中,userid(没有任何限定)是指来自任何表的非NULL值。

2
您可以解释计划并进行检查:
CREATE TABLE a (
  userid INT
, nm VARCHAR(32)
);
CREATE TABLE b (
  userid INT
, adr VARCHAR(32)
);
CREATE TABLE c (
  userid INT
, car VARCHAR(32)
);

EXPLAIN
SELECT *
FROM a
JOIN b USING(userid)
JOIN c USING(userid)
;
-- out                               QUERY PLAN                               
-- out -----------------------------------------------------------------------
-- out  Merge Join  (cost=152.17..334.01 rows=8946 width=250)
-- out    Merge Cond: (a.userid = c.userid)
-- out    ->  Merge Join  (cost=101.45..142.80 rows=2520 width=172)
-- out          Merge Cond: (a.userid = b.userid)
-- out          ->  Sort  (cost=50.72..52.50 rows=710 width=86)
-- out                Sort Key: a.userid
-- out                ->  Seq Scan on a  (cost=0.00..17.10 rows=710 width=86)
-- out          ->  Sort  (cost=50.72..52.50 rows=710 width=86)
-- out                Sort Key: b.userid
-- out                ->  Seq Scan on b  (cost=0.00..17.10 rows=710 width=86)
-- out    ->  Sort  (cost=50.72..52.50 rows=710 width=86)
-- out          Sort Key: c.userid
-- out          ->  Seq Scan on c  (cost=0.00..17.10 rows=710 width=86)

-- and with a full outer join:

EXPLAIN
SELECT *
FROM a
FULL JOIN b USING(userid)
FULL JOIN c USING(userid)
;
-- out                                  QUERY PLAN                                  
-- out -----------------------------------------------------------------------------
-- out  Merge Full Join  (cost=326.16..463.90 rows=8946 width=250)
-- out    Merge Cond: (c.userid = (COALESCE(a.userid, b.userid)))
-- out    ->  Sort  (cost=50.72..52.50 rows=710 width=86)
-- out          Sort Key: c.userid
-- out          ->  Seq Scan on c  (cost=0.00..17.10 rows=710 width=86)
-- out    ->  Sort  (cost=275.43..281.73 rows=2520 width=172)
-- out          Sort Key: (COALESCE(a.userid, b.userid))
-- out          ->  Hash Full Join  (cost=25.98..133.06 rows=2520 width=172)
-- out                Hash Cond: (a.userid = b.userid)
-- out                ->  Seq Scan on a  (cost=0.00..17.10 rows=710 width=86)
-- out                ->  Hash  (cost=17.10..17.10 rows=710 width=86)
-- out                      ->  Seq Scan on b  (cost=0.00..17.10 rows=710 width=86)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接