【问题标题】:MySQL full join (union) with ambiguous column names列名不明确的 MySQL 完全连接(联合)
【发布时间】:2014-05-29 17:11:25
【问题描述】:

我对 MySQL 在这么多年后仍然不支持 FULL JOIN 感到非常失望(为什么?)并且我必须使用 UNION 作为解决方法。说我在以下查询中遇到问题。我有两个表作为例子:

计算机

id   userid   owner   cpu   
1    1        Jack    3.4
2    1        Jack    3.4
3    2        Sara    3.0

监视器

id   userid   owner   inch  
1    1        Jack    22    
2    1        Jack    22    
3    3        Mark    17    
4    4        Luke    32    

基本上,我有一个已分配给所有者的具有规格的计算机列表。同样,我有一个带有规格的监视器列表,每个监视器都分配给一个所有者。我想按所有者将这两个表组合成这个结果:

id   userid   owner   cpu   id   userid   owner   inch  
1    1        Jack    3.4   1    1        Jack    22
2    1        Jack    3.4   2    1        Jack    22
3    2        Sara    3.0   null null     null    null 
null null     null    null  3    3        Mark    17
null null     null    null  4    4        Luke    32

我可以通过这个查询成功得到上面的结果:

SELECT * FROM computers AS a
LEFT OUTER JOIN monitors AS o on a.owner = o.owner
UNION
SELECT * FROM computers AS a
RIGHT OUTER JOIN monitors AS o on a.owner = o.owner

问题是:

  1. 不想在我的查询中使用 jolly 字符,不仅因为它效率不高,而且因为我只需要一些特定的列而不是全部
  2. 两个表都有不明确的列名(id、userid、owner),例如,我似乎不能按所有者排序。我知道我应该使用别名,但我不明白如何实现它
  3. 我必须使用 WHERE 语句,但由于列名不明确,我不明白如何实现它

现在总结一下我在伪查询中所说的话:

选择 id 作为 a_id,用户 ID 作为 a_userid,所有者作为 a_owner 但不是 cpu 来自 cpu = 3.4 的计算机

由所有者联合和加入:

SELECT id AS b_id, userid AS b_userid, owner AS b_owner, inch AS b_inch FROM monitor WHERE inch = 22

感谢您的宝贵时间。

【问题讨论】:

  • 我想知道这有多少只是一个虚构的例子,有多少不是。数据库设计很糟糕,每条记录中都重复了用户 ID 和名称。然后,您将一个人拥有的所有计算机和监视器组合在一起。做什么的?查看所有有趣的可能组合?使用给定的查询,您不会得到两个 Jack 记录,而是四个。至于不明确的列名:它们需要一个限定符。您已经在 a.owner = o.owner 中使用了它。那么问题出在哪里?
  • 我已经说过我的只是一个例子。当我说你有这样的结构时,相信我。如果您认为设计不好,那么您必须责怪whmcs.com。无论如何相信我。设计绝对好,功能齐全。这里的重点不是讨论设计的好坏,而是如何进行 FULL JOIN。
  • 好的。有时这样的旁白是有帮助的。我不是故意攻击:-) 我已经发布了一个答案。希望它能回答你所有的问题。

标签: mysql sql select join union


【解决方案1】:

这是 cpu = 3.4 和 Inch = 22 上的完全外连接。首先获取所有计算机并加入监视器,然后获取所有监视器并加入计算机。主表条件在 WHERE 子句中,外连接条件在 ON 子句中。

SELECT a.userid, a.owner, a.id as computer_id, o.id as monitor_id, o.inch
FROM computers AS a
LEFT OUTER JOIN monitors AS o 
  ON a.owner = o.owner and a.userid = o.userid and o.inch = 22
WHERE a.cpu = 3.4
UNION
SELECT o.userid, o.owner, a.id as computer_id, o.id as monitor_id, o.inch
FROM monitors AS o
LEFT OUTER JOIN computers AS a
  ON a.owner = o.owner and a.userid = o.userid and a.cpu = 3.4
WHERE o.inch = 22;

但是,这可以通过仅添加第一个选择未找到的记录来加快速度,即没有匹配计算机的监视器。然后您可以使用 UNION ALL 代替 UNION,这可以为 dbms 节省大量工作。您只需拿起外部连接表的不可为空的线圈。当它为 NULL 时,记录是外连接的。

SELECT a.userid, a.owner, a.id as computer_id, o.id as monitor_id, o.inch
FROM computers AS a
LEFT OUTER JOIN monitors AS o 
  ON a.owner = o.owner and a.userid = o.userid and o.inch = 22
WHERE a.cpu = 3.4
UNION ALL
SELECT o.userid, o.owner, a.id as computer_id, o.id as monitor_id, o.inch
FROM monitors AS o
LEFT OUTER JOIN computers AS a
  ON a.owner = o.owner and a.userid = o.userid and a.cpu = 3.4
WHERE o.inch = 22 and o.owner is null;

【讨论】:

    【解决方案2】:

    模拟full outer join 的另一种方法是使用子查询获取完整的值列表(在您的情况下为owners)。然后使用left outer join 引入其他值。根据您的描述:

    select c.id as c_id, c.userid as c_userid, o.owner as owner,
           m.id as m_id, m.user_id as m_userid, m.inch
    from (select owner from computers union
          select owner from monitors
         ) o left outer join
         computers c
         on o.owner = c.owner left outer join
         monitors m
         on o.owner = m.owner;
    

    但是,您提到的查询不会生成这些结果。它将为“Jack”生成四个结果。

    编辑:

    我怀疑你想匹配 owneriduser_id

    select c.id as c_id, c.userid as c_userid, o.owner as owner,
           m.id as m_id, m.user_id as m_userid, m.inch
    from (select owner, id, userid from computers union
          select owner, id, userid from monitors
         ) o left outer join
         computers c
         on o.owner = c.owner and o.userid = c.userid and o.id = c.id left outer join
         monitors m
         on o.owner = m.owner and o.userid = m.userid and o.id = m.id;
    

    【讨论】:

    • 正确。我的查询没有返回我所说的。我需要几分钟来“刷新”我的想法并理解你的方法。
    • 是的,第二个查询就是我要找的。有用。现在我需要几分钟来完全了解它是如何工作的,并了解我可以在哪里/如何注入我的 WHERE c_cpu = 3.4 AND m_inch = 22 加上 ORDER BY c_id (当然,我仍在使用伪查询)
    • @user1274113 。 . .你应该问另一个问题。 cmets 部分中的扩展问题和答案不受欢迎。
    猜你喜欢
    • 2017-06-09
    • 2018-04-22
    • 1970-01-01
    • 1970-01-01
    • 2015-03-31
    • 2011-12-20
    • 2016-09-13
    • 2021-08-13
    • 2013-12-17
    相关资源
    最近更新 更多