SQL如何搜索多对多的关系

时间:2008-12-08 13:32:01

标签: sql search many-to-many relational-division

我有一个包含两个主要表noteslabels的数据库。它们具有多对多关系(类似于stackoverflow.com对标签的问题)。我想知道的是如何使用SQL搜索使用多个标签的笔记?

例如,如果我有一个带有三个标签“one”,“two”和“three”的音符“test”,我有第二个音符“test2”,标签“one”和“two”是什么SQL查找将找到与标签“一”和“两个”相关联的所有笔记?

7 个答案:

答案 0 :(得分:8)

要获取两者标签“One”和“Two”的音符的详细信息:

select * from notes
where note_id in
( select note_id from labels where label = 'One'
  intersect
  select note_id from labels where label = 'Two'
)

答案 1 :(得分:1)

select * from notes a
inner join notes_labels mm on (mm.note = a.id and mm.labeltext in ('one', 'two') )

当然,请替换为您的实际列名,希望我对您的表的假设是正确的。

实际上,由于英语以及有时使用“和”这个词,你的问题可能存在一些歧义。如果你的意思是你想要看一个标记为“一个”而不是“两个”的注释,这应该有用(解释你的'和'意思是''给我看所有带有标签的注释'一'和/或全部带有'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')

编辑:感谢大家的建议,我脑子里的星期一齿轮有点慢......看起来我应该维基了!

答案 2 :(得分:1)

注意:我实际上没有测试过这个。它还假设您有一个名为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列作为复合主键。

答案 3 :(得分:0)

像这样......(你需要另一个链接表)

SELECT *
FROM Notes n INNER JOIN NoteLabels nl
ON n.noteId = nl.noteId
WHERE nl.labelId in (1, 2)

编辑:NoteLabel表将有两列,noteId和labelId,带有复合PK。

答案 4 :(得分:0)

假设您有一个规范化的数据库,您应该在noteslabels之间有另一个表

然后,您应该使用inner join将表连接在一起

  1. 使用bind-table(多对多表)
  2. 加入labels
  3. 使用上一个查询加入notes
  4. 示例:

    select * from ((labels l inner join labels_notes ln on l.labelid = ln.labelid) inner join notes n on ln.notesid = n.noteid)

    这样,您将两个表连接在一起。

    现在你需要添加的是where条款......但我会把它留给你。

答案 5 :(得分:0)

你没有说明这种多对多关系是如何实现的。我假设标签表是标签(noteid:int,label:varchar) - 主键是否跨越两者?

SELECT DISTINCT n.id from notes as n, notes_labels as nl WHERE n.id = nl.noteid AND nl.text in (label1, label2);

替换您的列名称,并为标签插入正确的占位符。

答案 6 :(得分:0)

如果您只需要一个列表,则可以使用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