Pregunta

Tengo una base de datos con dos tablas principales. notes y labels.Tienen una relación de muchos a muchos (similar a cómo stackoverflow.com tiene preguntas con etiquetas).Lo que me pregunto es ¿cómo puedo buscar una nota usando varias etiquetas usando SQL?

Por ejemplo, si tengo una nota "prueba" con tres etiquetas "uno", "dos" y "tres" y tengo una segunda nota "prueba2" con etiquetas "uno" y "dos", ¿cuál es la consulta SQL que ¿Encontrar todas las notas asociadas con las etiquetas "uno" y "dos"?

¿Fue útil?

Solución

Para obtener los detalles de las notas que tienen ambas etiquetas 'Uno' y 'Dos':

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

Otros consejos

Nota: en realidad no he probado esto. También supone que tiene una tabla de muchos a muchos llamada notes_labels, que puede no ser el caso en absoluto.

Si solo quieres las notas que tienen alguna de las etiquetas, es algo así

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

Si desea las notas que tienen TODAS las etiquetas, hay un poco de trabajo 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;

? siendo un marcador de posición SQL y 2 siendo el número de etiquetas que estaba buscando. Esto supone que la tabla de enlaces tiene ambas columnas de ID como clave principal compuesta.

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

Por supuesto, reemplace con sus nombres de columna reales, espero que mis suposiciones sobre su tabla sean correctas.

Y en realidad hay un poco de posible ambigüedad en su pregunta gracias al inglés y cómo a veces se usa la palabra 'y'. Si quiere decir que quiere ver, por ejemplo, una nota etiquetada 'uno' pero no 'dos', esto debería funcionar (interpretando su 'y' que significa ', muéstreme todas las notas con la etiqueta' uno 'y / más todos las notas con la etiqueta 'dos'). Sin embargo, si solo desea notas que tengan ambas etiquetas, esta sería una forma de hacerlo:

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

Editar: gracias por las sugerencias a todos, los engranajes de los lunes en mi cerebro son un poco lentos ... ¡parece que debería haberlo wiki!

Algo así ... (necesitará otra tabla de enlaces)

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

Editar : la tabla NoteLabel tendrá dos columnas, noteId y labelId, con un PK compuesto.

Suponiendo que tiene una base de datos normalizada, debería tener otra tabla en el medio. notes y labels

Entonces deberías utilizar un inner join para unir las mesas

  1. Disfruta el labels tabla con la tabla de enlace (tabla de muchos a muchos)
  2. Disfruta el notes tabla con la consulta anterior

Ejemplo:

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

De esa manera, habrás conectado ambas tablas.

Ahora lo que necesitas agregar es el where cláusula... pero eso se lo dejo a usted.

No dices nada acerca de cómo se realiza esta relación de muchos a muchos. Supongo que la tabla de etiquetas tiene Labels (noteid: int, label: varchar), ¿con una clave primaria que abarca ambos?

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

Reemplace con los nombres de sus columnas e inserte los marcadores de posición adecuados para las etiquetas.

Si solo necesita una lista, puede usar where exists para evitar duplicaciones. Si tiene varias etiquetas contra un nodo en sus criterios de selección, obtendrá filas duplicadas en el resultado. Aquí hay un ejemplo de <=>:

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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top