Sql关于两个left join 的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sql关于两个left join 的问题相关的知识,希望对你有一定的参考价值。

接着之前的问过的问题,也就是有三个表,一个库房列表room,一个货柜表hgb,一个商品表spb,已知库房表字段为:
库房名name,货柜表关键字段为所在库房kfname,货柜号hgno,商品表关键字段为所在库房kfname,商品编号spno,现在要统计每个库房多少个货柜,多少个商品,sql语句该怎么写,如果只查每个库房多少个货柜则可以
select a.name,count(b.hgno) from room a left join hgb b on a.name=b.kfname group by a.name

上面这句完全可以,关键还要查商品个数,如果写成:
select a.name,count(b.hgno),count(c.spno) from room a left join hgb b on a.name=b.kfname group by a.name left join spb c on a..name=c.name
查出的结果完全不对,请问高人,该怎么写?
上面那句我写错了,应该是:
select a.name,count(b.hgno),count(c.spno) from room a left join hgb b on a.name=b.kfname left join spb c on a.name=c.name group by a.name
就是这句也是不行的,请高人帮助!

你的错误在于货柜表hgb和商品表spb都是独立与房列表room关联的,而你却要放到一个连接语句中进行统计,这样就潜在的将货柜表hgb和商品表spb关联了
比如数据如下
room:name hgb:name ,hgno spb: name,spno
A A 1 A 1
B A 2 A 2
B 1 B 1
B 2 B 2
正常执行结果是
name count(b.hgno), count(c.spno)
A 2 2
B 2 2

但是按照你的语句是
name count(b.hgno), count(c.spno)
A 4 4
B 4 4
就是因为连续的星型连接造成的

你要实现的功能得这样
select R.name, R.Chg, S.Csp
from
(select a.name name,count(b.hgno) Chg from room a left join hgb b on a.name=b.kfname group by a.name) R,
(select a.name name,count(b.spno) Csp from room a left join spb b on a.name=b.kfname group by a.name) S
where R.name=S.name追问

感谢你的回答,你这个方法是对的,但我想再问下,假设如果我库房里还有其它的也要一起统计,那写法是不是跟你的写法相似,再加多个“(select a......) t”这种之类的呢?谢谢!

追答

嗯,可以用这种方法,因为是不同的分类,所以要在每个分类上统计,再连接

参考技术A 应该是这样才对:
select a.name,count(b.hgno),count(c.spno) from room a left join hgb b on a.name=b.kfname left join spb c on a..name=c.name group by a.name追问

不好意思,我上面写错了,我测试时就是你这样写的,但结果完全不正确,而且查出来的count(b.hgno),count(c.spno)
两个字段是一样的

关于 LEFT JOIN SQL 查询的 WHERE 帮助

【中文标题】关于 LEFT JOIN SQL 查询的 WHERE 帮助【英文标题】:Help with a WHERE on a LEFT JOIN SQL Query 【发布时间】:2010-09-18 03:45:42 【问题描述】:

我正在尝试构建一个查询,该查询将包含一列,指示用户是否已下载文档。我有一个名为 HasDownloaded 的表,其中包含以下列:id、documentID、memberID。找出用户是否下载了特定文档很容易;但我需要生成一个查询,结果如下所示:

name              id
----------------------
abc               NULL
bbb               2
ccc               53
ddd               NULL
eee               13

ID 并不重要;我感兴趣的是文档是否已下载(是否为NULL)。

这是我的查询:

SELECT Documents.name, HasDownloaded.id FROM Documents
LEFT JOIN HasDownloaded ON HasDownloaded.documentID = Documents.id
WHERE HasDownloaded.memberID = @memberID

问题是,只有在 HasDownloaded 表中存在指定用户的条目时才会返回值。我想保持这个简单,并且在 HasDownloaded 中只有条目用于 已下载的文档。因此,如果用户 1 下载了 abc、bbb 和 ccc,我仍然希望 ddd 和 eee 显示在结果表中,只是 id 为 NULL。但是 WHERE 子句只为我提供了哪些条目存在的值。

我不是一个 SQL 专家 - 有没有一个操作员可以在这里给我想要的东西?我应该采取不同的方法吗?或者这是不可能的?

【问题讨论】:

【参考方案1】:

将 WHERE 子句中的条件移至连接条件。

SELECT Documents.name, HasDownloaded.id FROM Documents
LEFT JOIN HasDownloaded ON HasDownloaded.documentID = Documents.id 
  AND HasDownloaded.memberID = @memberID 

当您想在 WHERE 子句中引用左连接表时,这是必需的。

【讨论】:

太棒了!这就是我一直在寻找的。​​span> 编辑:回答了我自己的问题。我能够找到一个很好的解释为什么这是真的。 weblogs.sqlteam.com/jeffs/archive/2007/05/14/…【参考方案2】:
WHERE HasDownloaded.memberId IS NULL OR HasDownloaded.memberId = @memberId

这是正常的做法。有些人会将其缩短为:

WHERE COALESCE(HasDownloaded.memberId, @memberId) = @memberId

正如 Matt B. 所示,您可以在您的 JOIN 条件下执行此操作 - 但我认为这更有可能使人们感到困惑。如果您不明白为什么将其移至 JOIN 子句有效,那么我强烈建议您远离它。

【讨论】:

【参考方案3】:

@Mark:我理解 JOIN 语法为何有效,但感谢您的警告。我确实认为您的建议更直观。我很想知道哪个更有效。所以我进行了快速测试(恐怕这相当简单,只有 14 行和 10 次试验):

在JOIN条件下:

AND HasDownloaded.memberID = @memberID
客户端处理时间:4.6 总执行时间:35.5 服务器回复的等待时间:30.9

在 WHERE 子句中:

WHERE HasDownloaded.memberId IS NULL OR HasDownloaded.memberId = @memberId
客户端处理时间:7.7 总执行时间:27.7 服务器回复的等待时间:22.0

看起来 WHERE 子句的效率稍微高了一点。有趣的!再次感谢你们两位的帮助。

【讨论】:

以上是关于Sql关于两个left join 的问题的主要内容,如果未能解决你的问题,请参考以下文章

关于VF中select left(right) join的准确用法

关于left join连接查询 两张表里有同名字段的问题

MySQL 的 2 个字段上的 SQL LEFT-JOIN

关于 LEFT JOIN SQL 查询的 WHERE 帮助

标准 SQL:使用 BETWEEN 通过两个条件进行 LEFT JOIN

两个 SQL LEFT JOINS 产生不正确的结果