Frage

Ich habe eine Datenbank mit zwei Tabellen notes und labels. Sie haben eine viele-zu-viele-Beziehung (ähnlich wie stackoverflow.com hat Fragen mit Etiketten). Was ich frage mich, wie kann ich für eine Notiz zu suchen mit mehreren Etiketten SQL verwenden?

Beispiel, wenn ich eine Notiz „test“ mit drei Etikett „eins“, „zwei“ habe, und „drei“ und ich habe eine zweite Note „test2“ mit Etikett „eins“ und „zwei“ Was ist die SQL Abfrage, die alle Notizen finden, die mit Etiketten „eins“ zugeordnet sind, und „zwei“?

War es hilfreich?

Lösung

die Details Notizen zu erhalten, die hat beide Etiketten 'One' und 'Zwei':

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

Andere Tipps

Hinweis: Ich habe nicht wirklich getestet dies. Es ist auch davon ausgegangen, Sie haben eine many-to-many-Tabelle mit dem Namen notes_labels, die überhaupt nicht der Fall sein kann.

Wenn Sie nur die Noten wollen, dass jede der Etiketten hat, dann ist es so etwas wie dieses

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

Wenn Sie die Noten wollen, dass alle der Etiketten haben, gibt es ein wenig zusätzliche Arbeit

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;

? ist ein SQL-Platzhalter und 2, um die Anzahl der Tags sind Sie für die Suche. Dies wird unter der Annahme, dass die Verknüpfungstabelle beide ID-Spalt als eine Verbindung Primärschlüssel hat.

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

Natürlich ersetzen mit Ihrem tatsächlichen Spaltennamen, hoffentlich meine Annahmen über den Tisch korrekt waren.

Und tatsächlich gibt es ein bisschen Zweideutigkeit in Ihrer Frage dank Englisch und wie das Wort ‚und‘ wird manchmal verwendet. Wenn Sie meinen, Sie sehen wollen, zum Beispiel, markiert eine Note ‚Eins‘, aber nicht ‚zwei‘, sollte diese Arbeit (Interpretieren ‚und‘ bedeuten, ‚zeigen Sie mir alle Noten mit dem Label‚ein‘und / plus alle die Noten mit dem Label ‚zwei‘). Wenn Sie jedoch nur Notizen wollen, dass beide Etiketten haben, wäre dies ein Weg, um darüber zu gehen:

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: Vielen Dank für die alle Vorschläge, die Montag Gänge in meinem Gehirn ein bisschen langsam ... sieht aus wie ich wiki'd es haben sollte

So etwas ... (Sie werden einen anderen Link-Tabelle müssen)

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

Bearbeiten :. Die NoteLabel Tabelle zwei Spalten hat, noteId und labelId, mit einem Composite-PK

Angenommen, Sie eine normalisierte Datenbank haben, sollten Sie einen anderen Tisch zwischen notes und labels

Sie sollten dann eine inner join verwenden, um die Tabellen miteinander zu verbinden

  1. Schließen Sie sich die labels Tabelle mit der bind-Tabelle (many-to-many-Tabelle)
  2. Schließen Sie sich die notes Tabelle mit der vorherige Abfrage

Beispiel:

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

Auf diese Weise haben Sie beide Tabellen miteinander verbunden sind.

Nun, was Sie hinzufügen müssen, ist die where Klausel ... aber ich werde das für Sie überlassen.

Sie sagen nichts darüber, wie dies viele-zu-viele-Beziehung realisiert wird. Ich gehe davon aus, dass die Etiketten Tabelle hat, wird Labels (NoteID: int, Label: varchar) - mit einem Primärschlüssel über beide

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

Ersetzen mit Spaltennamen, und legen Sie die richtigen Platzhalter für die Etiketten.

Wenn Sie nur eine Liste benötigen, können Sie where exists Doppelarbeit zu vermeiden verwenden. Wenn Sie mehrere Tags gegen einen Knoten in den Auswahlkriterien haben Sie doppelte Zeilen im Ergebnis. Hier ist ein Beispiel von 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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top