Mysql全外连接两个子查询

Posted

技术标签:

【中文标题】Mysql全外连接两个子查询【英文标题】:Mysql Full outer join two subqueries 【发布时间】:2021-07-13 03:06:25 【问题描述】:

我知道mysql不支持完全外连接,这样做你基本上必须左连接/右连接并进行联合。我有两张表,一张包含所有可能的键以及帐户的标签,另一个包含帐户中每个客户的键的值。我想获取帐户的所有键,如果它也有值记录值,我想按类型过滤。

CREATE TABLE IF NOT EXISTS `account_meta` (
  `account_meta_id` int(11) NOT NULL AUTO_INCREMENT,
  `type` varchar(100) COLLATE utf8mb4_bin NOT NULL,
  `key` varchar(200) COLLATE utf8mb4_bin NOT NULL,
  `value` varchar(300) COLLATE utf8mb4_bin NOT NULL,
  `rank` int(11) DEFAULT NULL,
  `account_id` int(11) NOT NULL,
  PRIMARY KEY (`account_meta_id`),
  KEY `account_id` (`account_id`),
  KEY `key` (`key`(191))
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;


INSERT INTO `account_meta` (`account_meta_id`, `type`, `key`, `value`, `rank`, `account_id`) VALUES(1, 'contact', 'Facebook', '', 1, 1);
INSERT INTO `account_meta` (`account_meta_id`, `type`, `key`, `value`, `rank`, `account_id`) VALUES(2, 'contact', 'Instagram', '', 2, 1);
INSERT INTO `account_meta` (`account_meta_id`, `type`, `key`, `value`, `rank`, `account_id`) VALUES(3, 'contact', 'Phone', '', 3, 1);
INSERT INTO `account_meta` (`account_meta_id`, `type`, `key`, `value`, `rank`, `account_id`) VALUES(4, 'contact', 'Email', '', 4, 1);
INSERT INTO `account_meta` (`account_meta_id`, `type`, `key`, `value`, `rank`, `account_id`) VALUES(5, 'contact', 'WeChat', '', 5, 1);
INSERT INTO `account_meta` (`account_meta_id`, `type`, `key`, `value`, `rank`, `account_id`) VALUES(6, 'stage', 'Sky', '', 6, 1);
INSERT INTO `account_meta` (`account_meta_id`, `type`, `key`, `value`, `rank`, `account_id`) VALUES(7, 'stage', 'Why', '', 7, 1);
INSERT INTO `account_meta` (`account_meta_id`, `type`, `key`, `value`, `rank`, `account_id`) VALUES(8, 'stage', 'My', '', 8, 1);


CREATE TABLE IF NOT EXISTS `client_contact` (
  `client_contact_id` int(11) NOT NULL AUTO_INCREMENT,
  `client_id` int(11) NOT NULL,
  `account_id` int(11) NOT NULL,
  `account_meta_id` int(200) NOT NULL,
  `value` varchar(1000) COLLATE utf8mb4_bin NOT NULL,
  PRIMARY KEY (`client_contact_id`),
  KEY `client_id` (`client_id`),
  KEY `key` (`account_meta_id`),
  KEY `account_id` (`account_id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

INSERT INTO `client_contact` (`client_contact_id`, `client_id`, `account_id`, `account_meta_id`, `value`) VALUES(2, 11, 1, 1, 'https://www.yahoo.com');
INSERT INTO `client_contact` (`client_contact_id`, `client_id`, `account_id`, `account_meta_id`, `value`) VALUES(3, 11, 1, 2, 'Serua');
INSERT INTO `client_contact` (`client_contact_id`, `client_id`, `account_id`, `account_meta_id`, `value`) VALUES(4, 11, 1, 3, 'abs');
INSERT INTO `client_contact` (`client_contact_id`, `client_id`, `account_id`, `account_meta_id`, `value`) VALUES(6, 11, 1, 5, 'oragnas');
INSERT INTO `client_contact` (`client_contact_id`, `client_id`, `account_id`, `account_meta_id`, `value`) VALUES(7, 12, 1, 5, 'oragnas');

https://www.db-fiddle.com/f/jHzANXZDjykpSWMcsX5a5f/5

基本上我希望第一个查询结果完全外连接到 mysql (5.7) 中的第二个查询结果。第三个查询是我尝试这样做,但无论我做什么,我都无法让它返回。我试过做交叉连接,但是用重复的 account_meta_id 得到重复的记录,第一条记录的值是另一个 null。我尝试通过添加 case/when account_meta_id 是否相同来做到这一点

【问题讨论】:

编辑您的问题并显示您正在讨论的查询。例如,join 的键是什么? account_meta_id,account_id 是连接两个表的键 【参考方案1】:

左连接/右连接绝对不是模拟完全连接的最佳方式(它既太昂贵,又会产生删除重复结果的开销,这很愚蠢)。

一种方法是构造所有键,然后只使用left join

with am as (
      select *
      from `account_meta`
      where account_id = 1 and `type` = 'contact'
     ),
     cc as (
      select *
      from `client_contact`
      where account_id = 1 and client_id = 11
     )
select am.*, cc.*
from ((select <key>  -- whatever the key is for the join
       from am
      ) union   -- on purpose to remove duplicates
      (select <key>
       from cc
      )
     ) k left join
     cc
     on cc.<key> = k.<key> left join
     am
     on am.<key> = k.<key>;

【讨论】:

不能用with,mysql 5.7中的数据

以上是关于Mysql全外连接两个子查询的主要内容,如果未能解决你的问题,请参考以下文章

MySql-多表查询

连接查询与子查询

mysql-数据库查询语句汇总

MySQL单表的CRUD及多表查询

mysql 两个子查询很快 ,再连接查询变的很慢,怎么分析其原因

多表连接查询子查询多种查询语句(只要你想,这里都有)