mySQL 中的完全外连接计数

Posted

技术标签:

【中文标题】mySQL 中的完全外连接计数【英文标题】:Count of full outer join in mySQL 【发布时间】:2018-09-07 18:52:30 【问题描述】:

我正在尝试显示完整外连接表中的总行数。我有以下代码,但 mysql 说重复列有错误。这 2 个表(演员和导演)具有相同的列,因为它们应该在各自的类别中提供类似的信息。

SELECT COUNT(*) FROM 
(SELECT * FROM directors LEFT OUTER JOIN actors
ON directors.name = actors.name
UNION
SELECT * FROM directors RIGHT OUTER JOIN actors
ON directors.name = actors.name) AS table1;

如何修复代码以使其正常运行?仅供参考,括号内的代码运行良好。只有在我输入 SELECT COUNT(*) 子句后才会出现问题。

【问题讨论】:

来自 MySQL 的确切错误消息是什么? 【参考方案1】:

因为有两个name 列,一个来自directors 表,另一个来自actors 表,而你select * 会让DB 引擎混淆你想要获取哪个名称。

如果你只想count总数你可以试试这个。

SELECT COUNT(*) FROM 
(
    SELECT directors.name FROM directors LEFT OUTER JOIN actors
        ON directors.name = actors.name
    UNION
    SELECT directors.name FROM directors RIGHT OUTER JOIN actors
        ON directors.name = actors.name
) table1;

注意

我建议使用select 清除列并避免使用select *

【讨论】:

数据库中可能只有两个名字和数百条记录。 百万数据在OP中没有提到,这个OP的问题是如何解决错误。 啊,我现在明白你的意思了,在不知道其余列的情况下,你只能说名字;我更关心的是“bob”可能会在其他列中出现多次,而其他列中的数据不同,这会将所有“bob”记录合并为一个。【参考方案2】:

最好将右连接部分更改为非冗余,然后添加单独的 很重要。

通用版:

SELECT (SELECT COUNT(*) FROM A LEFT JOIN B ON A.x = B.x) 
+ (SELECT COUNT(*) FROM B LEFT JOIN A ON B.x = A.x WHERE A.x IS NULL)
AS outerJoinSize
;

注意:我将 RIGHT JOIN 更改为 LEFT JOIN 并交换了表格;根据我的经验,RIGHT JOIN 只会使查询更难阅读(尤其是在涉及多个联接时)。


一个完全不同的选择......

SELECT 
( SELECT SUM(dc1.c * IFNULL(ac1.c, 1)) AS jc
  FROM (SELECT name, COUNT(*) AS c FROM directors GROUP BY name) AS dc1 
  LEFT JOIN (SELECT name, COUNT(*) AS c FROM actors GROUP BY name) AS ac1
     ON dc1.name = ac1.name)
+ (SELECT SUM(IF(dc2.name IS NULL, ac2.c, 0)) AS jc
   FROM (SELECT name, COUNT(*) AS c FROM actors GROUP BY name) AS ac2
   LEFT JOIN (SELECT name, COUNT(*) AS c FROM directors GROUP BY name) AS dc2 
      ON ac2.name = dc2.name)

...根据加入字段计算出有多少匹配项(导演中的 3 个“Bob”实例和演员中的 2 个实例意味着该名称的 6 个加入结果)。

【讨论】:

您的计数不等于 UNION 的计数,请参阅此小提琴sqlfiddle.com/#!9/b538c5/5 我得看看,但我正试图获得交叉连接的计数; UNION [DISTINCT] 不一定可以复制。 我计算出的 outerJoinSize 根据我在脑海中用该数据计算出来的交叉连接看起来是正确的;小提琴中的当前 UNION ALL 无法得出相同的答案,因为联合的第二个查询需要使用 WHERE a.x IS NULL 消除第一个查询中的重复项【参考方案3】:

我不确定您对full join 的了解。但是在 MySQL 中实现它的最佳方式是使用两个left joins 和一个union

select count(*)
from ((select name from directors) union -- on purpose
      (select name from actors)
     ) da left join
     directors d
     on da.name = d.name left join
     actors a
     on da.name = a.name;

但是,如果我不得不猜测,您只需要两个表之间不同名称的数量。如果是这样:

select count(*)
from ((select name from directors) union -- on purpose
      (select name from actors)
     ) da 

【讨论】:

以上是关于mySQL 中的完全外连接计数的主要内容,如果未能解决你的问题,请参考以下文章

MySQL面试题

MySQL - 使用 COUNT 在同一个表上进行完全外连接

mysql内连接和外连接的区别

SQL内连接与外连接的区别

SQL中的左连接与右连接,内连接有啥区别

Mysql全外连接两个子查询