MySQL选择左连接不同?

Posted

技术标签:

【中文标题】MySQL选择左连接不同?【英文标题】:MySQL Select Distinct with Left Join? 【发布时间】:2016-11-13 16:57:00 【问题描述】:

我正在尝试获取没有公司级别注释的company_id 列表。但是,该公司可能有位置级别的注释。

company
-------------------------
company_id  name  deleted
1           Foo   0
2           Bar   0
3           Baz   0

location
-----------------------
location_id  company_id
6            1
7            2
8            3

note
-----------------------------------------
note_id  company_id  location_id  deleted
10       2           6            0         // location-level note
11       1           7            0         // location-level note
12       null        8            0         // location-level note
13       2           null         0         // company-level note

我希望我的结果表是这样的:

company_id  name
1           Foo
3           Baz

更新

Foo/company_id = 1 没有公司级别的注释,因为该注释还有一个location_id,这使其成为位置级别的注释。公司级别的注释是仅链接到公司(而不是位置)的注释。

更新结束

我试过做这样的事情,但它返回一个空集,所以我不确定它是否有效,没有任何公司没有公司级别的注释,或者我做错了什么。

SELECT DISTINCT 
c.company_id, 
c.name
FROM company AS c
LEFT JOIN note AS n
ON c.company_id = n.company_id
WHERE 
c.deleted = 0 AND
n.deleted = 0 AND
n.location_id IS NOT NULL AND 
n.location_id != 0 AND
c.company_id = (SELECT MAX(company_id) FROM company)

Mike 修改后接受的答案

SELECT
    company_id,
    name
FROM company
WHERE 
    deleted = 0 AND
    company_id NOT IN (
        SELECT DISTINCT 
            c.company_id
        FROM company AS c 
        INNER JOIN note AS n 
        ON c.company_id = n.company_id 
        WHERE (
            n.deleted = 0 AND
                (n.location_id IS NULL OR 
                n.location_id = 0)
        )
    );

【问题讨论】:

Deleted 列在样本数据中缺失,这些条件n.deleted = 0 AND n.location_id IS NOT NULL AND n.location_id != 0 会将Left join 变成Inner join c.company_id = (SELECT MAX(company_id) FROM company) 这将确保结果只有一个 company_id @Prdp 更新了问题以包含已删除的列。如何在仅查找公司级注释的同时防止将左转为内部联接? 注意(NULL的特殊情况除外)LEFT JOIN n ... WHERE nINNER JOIN n相同 @GreeKatrina 我没有得到结果表的逻辑,你能解释一下吗 【参考方案1】:

考虑这一点的最简单方法是首先找到所有有公司级别注释的公司,您可以这样做

 select distinct c.company_id
   from company c 
 inner join notes n 
     on c.company_id = n.company_id 
  where n.location_id is null;

然后只需从公司选择中删除这些公司:

select company_id,
       name
  from company
 where company_id not in (select distinct c.company_id
                            from company c 
                          inner join notes n 
                              on c.company_id = n.company_id 
                           where n.location_id is null);

*更新为使用内连接而不是逗号分隔的连接。

【讨论】:

当有人已经在使用明确的Joins时,永远不要建议comma separated join 我之前没见过逗号分隔的连接,能否请您按照@Prdp 的建议使用关键字更新答案? 我刚刚在您的查询中添加了几个 where 子句,它可以工作(更新的问题)。谢谢!【参考方案2】:
SELECT DISTINCT c.* 
  FROM company c 
  LEFT 
  JOIN note n 
    ON n.company_id = c.company_id 
   AND n.location_id IS NULL 
 WHERE n.note_id IS NULL;

【讨论】:

以上是关于MySQL选择左连接不同?的主要内容,如果未能解决你的问题,请参考以下文章

mysql左连接右连接(查询两张表不同的数据)

Linq:选择不同的对象左连接

mysql左连接右连接(查询两张表不同的数据)

Mysql:使用左连接选择未按预期工作

左连接和右连接有啥区别

MySQL选择左连接为空的行