首页 > 解决方案 > Mysql全外连接两个子查询

问题描述

我知道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 是否相同来做到这一点

标签: jquerymysqlsqldatabase

解决方案


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

一种方法是构造所有键,然后仅使用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>;

推荐阅读