Pergunta

Eu tenho um banco de dados com duas tabelas principais notes e labels. Eles têm um relacionamento muitos-para-muitos (semelhante à forma como stackoverflow.com tem perguntas com etiquetas). O que eu estou querendo saber é como eu posso procurar uma nota utilizando várias etiquetas usando SQL?

Por exemplo, se eu tenho uma nota "teste" com três rótulos "um", "dois" e "três" e eu tenho uma segunda nota "test2" com rótulos "um" e "dois" o que é o SQL consulta que vai encontrar todas as notas que estão associados com rótulos "um" e "dois"?

Foi útil?

Solução

Para obter os detalhes de notas que têm ambos rótulos 'One' e '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'
)

Outras dicas

Nota: Eu realmente não tenho testado isso. Ele também assume que você tem uma relação muitos-para-muitos tabela chamado notes_labels, que pode não ser o caso.

Se você quiser apenas as notas que com uma das etiquetas, é ser algo como isto

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 (?, ?)

Se você quiser as notas que têm todos os rótulos, há um pouco de trabalho extra

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;

? sendo um espaço reservado SQL e 2 sendo o número de tags que você estava procurando. Isso supõe que a tabela de link tem duas colunas de identificação como uma chave primária composta.

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

É claro, substitua com seus nomes de coluna reais, espero que minhas suposições sobre sua mesa estavam corretas.

E, na verdade, há um pouco de uma possível ambigüidade na sua pergunta graças ao Inglês e como a palavra 'e' é por vezes utilizado. Se você quer dizer que você quer ver, por exemplo, uma nota com a tag 'um', mas não 'dois', isso deve funcionar (interpretando o seu 'e' quer dizer, um 'e / plus all 'me todas as notas com etiqueta mostrar' as notas com etiqueta 'dois'). No entanto, se você quiser apenas as notas que têm ambos os rótulos, esta seria uma maneira de fazê-lo:

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

EDIT: Obrigado pelas sugestões todos, as engrenagens de segunda-feira em meu cérebro são um pouco lento ... parece que eu deveria ter wiki'd it

!

Algo assim ... (você vai precisar de outra tabela link)

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

Editar :. A tabela de NoteLabel terá duas colunas, NoteID e labelId, com uma PK compósito

Supondo que você tenha um banco de dados normalizado, você deve ter outra tabela entre notes e labels

Você deve então usar um inner join para unir as tabelas juntos

  1. Junte-se a tabela de labels com mesa ligam a (muitos-para-muitos tabela)
  2. Junte-se a tabela de notes com a consulta anterior

Exemplo:

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

Dessa forma, você ter ligado ambas as tabelas juntos.

Agora, o que você precisa fazer é adicionar a cláusula where ... mas vou deixar isso para você.

Você não diz nada sobre como esse relacionamento muitos-para-muitos é realizado. Presumo que a tabela de etiquetas tem é etiquetas (NoteID: int, rótulo: varchar) - com uma chave primária abrangendo tanto

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

Substitua com seus nomes de coluna e insira os espaços reservados apropriados para os rótulos.

Se você só precisa de uma lista, você pode usar where exists para evitará a duplicação. Se você tem várias tags contra um nó em seus critérios de seleção você vai ter linhas duplicadas no resultado. Aqui está um exemplo de 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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top