有趣的多对多sql连接
Posted
技术标签:
【中文标题】有趣的多对多sql连接【英文标题】:Interesting Many-many sql join 【发布时间】:2010-09-18 06:10:18 【问题描述】:我有三个相关的表“A(id, val)”、“B(id, val)”和一个值为“AB(aid, bid, val)”的链接表
我正在查询 B 以带回 A 值,例如:
SELECT A.*
FROM A INNER JOIN AB ON A.id = AB.aid INNER JOIN B ON AB.bid = B.id
WHERE B.val = 'foo';
每个 A 都有很多 B,每个 B 都有很多 A。
我要崩溃的问题是需要过滤集合,以便查询仅在 AB.val 是任何给定 A/B 对的最大值时才返回行
例如如果我有数据:
一个
id val
1 something
2 somethingelse
B
id val
1 foo
2 bar
AB
aid bid val
1 1 3
1 2 2
2 1 1
2 2 4
我只想选择 AB 的第一行和最后一行,因为它们是每个 A 的最大值,然后能够查询 B.val = 'foo' 以仅返回第一行。我不知道如何仅限制 AB 表中的 max val 行。
我能得到的最好的是
SELECT *
FROM A
INNER JOIN
(SELECT aid, bid, MAX(val) AS val FROM AB GROUP BY aid) as AB
ON A.id = AB.aid
INNER JOIN B ON AB.id = B.id
WHERE B.val = 'foo'
但这并不完全奏效。首先,它只是感觉是错误的方法,其次,它返回了错误的投标值。也就是说,从子查询返回的出价不一定与 max(val) 来自同一行。我相信这是一个已知的分组问题,当未为排序规则或分组指定列时选择返回的值是未定义的。
我希望上面的一些内容是有道理的,在过去的几个小时里,我一直在为此苦苦挣扎,任何帮助都将不胜感激。谢谢。
(对于那些想知道的人,它的实际用途是用于字典后端,其中 A 是单词表,B 是音素表。AB 是带有“位置”列的词素表。查询是查找所有单词以指定的音素结尾。(音素是单词的声音,用法类似于国际音标)
【问题讨论】:
【参考方案1】:我认为您需要先进行另一个联接才能获得每个 a.id 的 ab 的最大 val。
类似这样的:
select a.*
from a
left join (
select aid, max(val) as val
from ab
group by aid
) abmax on abmax.aid=a.id
inner join ab on ab.aid=abmax.aid and ab.val=abmax.val
inner join b on b.id=ab.bid
where b.val='foo'
【讨论】:
【参考方案2】:这是我刚刚测试的另一种方法:
select a.*
from ab
inner join b on(ab.bid=b.id)
inner join a on (ab.aid=a.id)
where ab.val = (select max(val) from ab AS ab2 where ab2.aid = ab.aid)
and b.val='foo'
【讨论】:
【参考方案3】:我经常使用以下技巧来获得最大的每组:
SELECT a.*
FROM ab AS ab1
LEFT OUTER JOIN ab AS ab2 ON (ab1.aid = ab2.aid AND ab1.val < ab2.val)
JOIN a ON (ab1.aid = a.id)
JOIN b ON (ab1.bid = b.id)
WHERE ab2.aid IS NULL
AND b.val = 'foo';
诀窍是在外部连接中将 AB 表连接到自身。返回 ab1,其中不存在具有相同的辅助值和更大的值的行。因此,对于给定的辅助值,ab1 的每组行的 val 最大。
【讨论】:
当 ab 中有多个行且具有相同的帮助时,这种连接可能会变得非常昂贵。如果 ab 中只有 5 行相同,则这 5 行将在过滤之前产生 10 个结果行。六个将产生 16 行,依此类推。使用 max() 效率更高。 是的,不同的技术适用于不同的情况。【参考方案4】:我不确定您使用的是哪个 sql,但在 MS SQL 中,我创建了一个表值数据库函数来返回表 A 中的最大值,然后将其连接到表 B。我发现这比复杂连接更容易理解稍后我会回顾我的查询。
【讨论】:
【参考方案5】:SELECT *
FROM
(
SELECT
A.*,
(SELECT top 1 AB.BID FROM AB WHERE A.AID = AB.AID ORDER BY AB.val desc) as BID
FROM A
) as Aplus
JOIN B ON Aplus.BID = B.BID
【讨论】:
以上是关于有趣的多对多sql连接的主要内容,如果未能解决你的问题,请参考以下文章