如何select多对多的一对一关系table

How to select one to one relations from many to many table

我有一个数据库,用于保存书籍及其作者。在我的模型中,一位作者可以拥有多本书,而一本书可以由多位作者撰写。示例:

AUTHOR_ID|BOOK_ID
1|100
1|200
1|300
2|300
3|300
4|400

我试图找到只写过一本书的作者,并且那本书必须仅由该作者单独撰写。在上面的例子中,只有有效的作者是 AUTHOR_ID = 4.
我需要写一个 select 来获取满足上述要求的作者 ID,我怎样才能快速高效地写 select 来做到这一点?

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))

这是一个单独的答案,因为第一个答案是错误的。

如果您的数据库支持 window 函数,一种方法是:

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 子句或 joins:

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);