SQL如何搜索多对多关系
-
20-08-2019 - |
题
我有一个数据库有两个主要表 notes
和 labels
.他们有许多对多关系(类似于如何stackoverflow.com 有问题与标签)。什么我不知道是怎么我可以寻找一个注意使用多个标签使用SQL?
例如,如果我有注意"测试"与三个标签"one","two",并"三"我有一个第二意"测试2"标签"一"和"两个"是什么SQL query,将会找到所有的注意到,有关带有标签的"一"和"两个"?
解决方案
要获得的具有的两个强>标签 '一' 和 '二' 的注释的细节:
select * from notes
where note_id in
( select note_id from labels where label = 'One'
intersect
select note_id from labels where label = 'Two'
)
其他提示
请注意:我还没有实际测试过这一点。它还假定你有一个多到多台名为notes_labels,这可能不是在所有的情况。
如果你只是想将具有任何标签的音符,它是这样的
SELECT DISTINCT n.id, n.text
FROM notes n
INNER JOIN notes_labels nl ON n.id = nl.note_id
INNER JOIN labels l ON nl.label_id = l.id
WHERE l.label IN (?, ?)
如果您希望拥有所有标签的笔记,还有一些额外的工作。
SELECT n.id, n.text
FROM notes n
INNER JOIN notes_labels nl ON n.id = nl.note_id
INNER JOIN labels l ON nl.label_id = l.id
WHERE l.label IN (?, ?)
GROUP BY n.id, n.text
HAVING COUNT(*) = 2;
?作为一个SQL占位符和2是你正在寻找的标签数量。这是假设该链接表中有两列ID作为化合物主键。
select * from notes a
inner join notes_labels mm on (mm.note = a.id and mm.labeltext in ('one', 'two') )
当然,替换你的实际列名,希望我的餐桌的假设是正确的。
和实际上有一点可能含糊不清你的问题由于英语以及如何词“和”有时使用。如果你的意思是你想看到的,例如,一记标记“一”,但不是“二”,这应该工作(解释你的“和”的意思,“给我所有标签的笔记‘一’和/加上所有注释标签为“两化”)。不过,如果你只是想有两个标签,票据,这将是去了解的一种方式:
select * from notes a
where exists (select 1 from notes_labels b where b.note = a.id and b.labeltext = 'one')
and exists (select 1 from notes_labels c where c.note = a.id and c.labeltext = 'two')
编辑:感谢您的建议大家,在我的大脑周一齿轮是有点慢......貌似我应该已经wiki'd它
这样的事情...(你需要另一个链接表)
SELECT *
FROM Notes n INNER JOIN NoteLabels nl
ON n.noteId = nl.noteId
WHERE nl.labelId in (1, 2)
修改强>:所述NoteLabel表将有两列,noteId和labelId,与复合PK
假设你已经标准化数据库,你应该有另一种表在之间 notes
和 labels
你应该再用一个 inner join
加入表一起
- 加入
labels
表与绑定表(很多对多表) - 加入
notes
表与先前的查询
例如:
select * from ((labels l inner join labels_notes ln on l.labelid = ln.labelid)
inner join notes n on ln.notesid = n.noteid)
这样,你已经连接两个表格合在一起。
现在你需要补充的是的 where
条款。但我会离开你。
您没有谈到这个许多一对多的关系是如何实现的。我假定标签表具有被标签(noteid:INT,标签:VARCHAR) - 具有主键跨越两个
SELECT DISTINCT n.id from notes as n, notes_labels as nl WHERE n.id = nl.noteid AND nl.text in (label1, label2);
替换列名,并插入适当的占位符的标签。
如果你只需要一个列表,你可以使用where exists
以避免重复。如果你对一个节点的多个标签在你的选择标准,你会得到的结果重复的行。下面是where exists
的示例:
create table notes (
NoteID int not null primary key
,NoteText varchar (max)
)
go
create table tags (
TagID int not null primary key
,TagText varchar (100)
)
go
create table note_tag (
NoteID int not null
,TagID int not null
)
go
alter table note_tag
add constraint PK_NoteTag
primary key clustered (TagID, NoteID)
go
insert notes values (1, 'Note A')
insert notes values (2, 'Note B')
insert notes values (3, 'Note C')
insert tags values (1, 'Tag1')
insert tags values (2, 'Tag2')
insert tags values (3, 'Tag3')
insert note_tag values (1, 1) -- Note A, Tag1
insert note_tag values (1, 2) -- Note A, Tag2
insert note_tag values (2, 2) -- Note B, Tag2
insert note_tag values (3, 1) -- Note C, Tag1
insert note_tag values (3, 3) -- Note C, Tag3
go
select n.NoteID
,n.NoteText
from notes n
where exists
(select 1
from note_tag nt
join tags t
on t.TagID = nt.TagID
where n.NoteID = nt.NoteID
and t.TagText in ('Tag1', 'Tag3'))
NoteID NoteText
----------- ----------------
1 Note A
3 Note C