Domanda

Ho un database con due tabelle principali notes e labels. Hanno una relazione molti-a-molti (simile a come stackoverflow.com ha domande con le etichette). Quello che mi chiedo è come posso cercare una nota usando più etichette usando SQL?

Ad esempio se ho una nota " test " con tre etichette " uno " ;, " due " ;, e " tre " e ho una seconda nota " test2 " con etichette " una " e " due " qual è la query SQL che troverà tutte le note associate alle etichette " una " e " due " ;?

È stato utile?

Soluzione

Per ottenere i dettagli delle note che hanno entrambe le etichette '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'
)

Altri suggerimenti

Nota: non l'ho ancora testato. Presuppone anche che tu abbia una tabella molti-a-molti chiamata notes_labels, che potrebbe non essere affatto il caso.

Se vuoi solo le note che hanno una delle etichette, è qualcosa del genere

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 vuoi le note con TUTTE le etichette, c'è un po 'di lavoro 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;

? essendo un segnaposto SQL e 2 il numero di tag che stavi cercando. Ciò presuppone che la tabella dei collegamenti abbia entrambe le colonne ID come chiave primaria composta.

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

Naturalmente, sostituiscilo con i nomi delle tue colonne attuali, spero che i miei presupposti sulla tua tabella fossero corretti.

E in realtà c'è un po 'di possibile ambiguità nella tua domanda grazie all'inglese e al modo in cui la parola' e 'viene talvolta usata. Se vuoi dire che vuoi vedere, ad esempio, una nota taggata "uno" ma non "due", questo dovrebbe funzionare (interpretando il tuo "e" intendere ", mostrami tutte le note con l'etichetta" uno "e / più tutto le note con etichetta 'due'). Tuttavia, se desideri solo note con entrambe le etichette, questo sarebbe un modo per procedere:

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

Modifica: grazie per i suggerimenti a tutti, gli ingranaggi del lunedì nel mio cervello sono un po 'lenti ... sembra che avrei dovuto fare il wiki!

Qualcosa del genere ... (avrai bisogno di un'altra tabella di collegamenti)

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

Modifica : la tabella NoteLabel avrà due colonne, noteId e labelId, con un PK composito.

Supponendo che tu abbia un database normalizzato, dovresti avere un'altra tabella tra notes e labels

Dovresti quindi utilizzare un inner join per unire le tabelle

  1. Unisciti alla select * from ((labels l inner join labels_notes ln on l.labelid = ln.labelid) inner join notes n on ln.notesid = n.noteid) tabella con la bind-table (tabella molti-a-molti)
  2. Unisciti alla where tabella con la query precedente

Esempio:

<=>

In questo modo, hai collegato entrambe le tabelle insieme.

Ora quello che devi aggiungere è la <=> clausola ... ma la lascio a te.

Non dici nulla su come si realizza questa relazione molti-a-molti. Suppongo che la tabella delle etichette sia Labels (noteid: int, label: varchar) - con una chiave primaria che si estende su entrambi?

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

Sostituisci con i nomi delle colonne e inserisci i segnaposto appropriati per le etichette.

Se hai solo bisogno di un elenco, puoi usare where exists per evitare duplicazioni. Se hai più tag su un nodo nei tuoi criteri di selezione otterrai risultati duplicati nel risultato. Ecco un esempio di <=>:

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top