如何从多对多表中选择一对一关系
Posted
技术标签:
【中文标题】如何从多对多表中选择一对一关系【英文标题】:How to select one to one relations from many to many table 【发布时间】:2016-03-07 12:48:20 【问题描述】:我有一个数据库,用于保存书籍及其作者。在我的模型中,一个作者可以有很多本书,而一本书可以由多个作者写。示例:
AUTHOR_ID|BOOK_ID
1|100
1|200
1|300
2|300
3|300
4|400
我正在努力寻找只写了一本书的作者,而那本书只能由该作者本人撰写。在上面的例子中,只有有效的作者是 AUTHOR_ID = 4。 我需要编写一个选择来获取满足上述要求的作者 ID,我该如何编写快速高效的选择来做到这一点?
【问题讨论】:
【参考方案1】:select *
from BookAuthors t1
where not exists (select * from BookAuthors t2
where t2.BOOK_ID = t1.BOOK_ID
and t2.Author_ID <> t1.Author_ID)
and not exists (select * from BookAuthors t3
where t3.Author_ID = t1.Author_ID
and t3.BOOK_ID <> t1.BOOK_ID)
第一个NOT EXISTS
是为了确保同一个bookid 没有第二个作者。
第二个NOT EXISTS
用于确保相同的 Author_ID 没有写过另一本书。
组合版:
select *
from BookAuthors t1
where not exists (select * from BookAuthors t2
where (t2.BOOK_ID = t1.BOOK_ID
and t2.Author_ID <> t1.Author_ID)
or (t2.Author_ID = t1.Author_ID
and t2.BOOK_ID <> t1.BOOK_ID))
【讨论】:
【参考方案2】:这是一个单独的答案,因为第一个是错误的。
如果你的数据库支持窗口函数,一种方法是:
select Author_ID
from (select ba.*, count(*) over (partition by Author_ID) as numBooks,
count(*) over (partition by Book_ID) as numAuthors
from BookAuthors ba
) ba
where numBooks = 1 and numAuthors = 1;
通过将条件移至where
子句或join
s 也有多种方法:
select ba.*
from BookAuthors ba
where Author_ID in (select Author_Id from BookAuthors group by Author_Id having count(*) = 1) and
Book_ID in (select Author_Id from BookAuthors group by Book_ID having count(*) = 1);
【讨论】:
以上是关于如何从多对多表中选择一对一关系的主要内容,如果未能解决你的问题,请参考以下文章
MySQL 基础 -- 多表关系(一对一1对多(多对一)多对多)多表查询(内连接外连接自连接子查询(嵌套查询)联合查询 union)笛卡儿积