J'ai une base de données avec deux tables principales notes
et labels
. Ils ont une relation plusieurs-à-plusieurs (similaire à la façon dont stackoverflow.com a des questions avec des étiquettes). Ce que je me demande est comment puis-je rechercher une note en utilisant plusieurs étiquettes en utilisant SQL? Par exemple si j'ai une note "test" avec trois étiquettes "un", "deux" et "trois" et j'ai une deuxième note "test2" avec les étiquettes "un" et "deux" quel est le Requête SQL qui trouvera toutes les notes associées aux étiquettes "un" et "deux"?SQL comment rechercher une relation plusieurs à plusieurs
Répondre
Pour obtenir les détails des notes qui ont les deux étiquettes de One »et « 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'
)
Merci! seule solution qui donne le résultat correct jusqu'à présent! "... Requête SQL qui trouvera toutes les notes associées aux étiquettes 'un' et 'deux'?" –
Ah, vous l'avez. J'ai maintenant une syntaxe alternative sur la mienne, mais je n'ai pas vu la tienne jusqu'à maintenant. +1 – Kev
select * from notes a
inner join notes_labels mm on (mm.note = a.id and mm.labeltext in ('one', 'two'))
Bien sûr, remplacez par vos noms de colonnes réels, j'espère que mes hypothèses sur votre table étaient correctes.
En fait, il y a un peu d'ambiguïté possible dans votre question grâce à l'anglais et à la façon dont le mot «et» est parfois utilisé. Si vous voulez dire que vous voulez voir, par exemple, une note étiquetée 'un' mais pas 'deux', cela devrait fonctionner (interpréter votre 'et' signifier, 'montrer toutes les notes avec l'étiquette' un 'et/ou tout les notes avec l'étiquette «deux»). Toutefois, si vous ne voulez notes qui ont les deux étiquettes, ce serait une façon d'aller à ce sujet:
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: Merci pour les suggestions tout le monde, les rapports lundi dans mon cerveau sont un peu lent ... On dirait que je devrais l'avoir wiki!
Les parenthèses sont toutes redondantes mais pourraient être utiles si vous construisiez des requêtes similaires. – Kev
Cette condition ne sera jamais vraie: (mm.labeltext = 'un' et mm.labeltext = 'deux') –
(mm.labeltext = 'un' OU mm.labeltext = 'deux') ou mm.labeltext IN ('un', 'deux') –
Quelque chose comme ça ... (vous aurez besoin d'une autre table de lien)
SELECT *
FROM Notes n INNER JOIN NoteLabels nl
ON n.noteId = nl.noteId
WHERE nl.labelId in (1, 2)
Modifier: la table NoteLabel aura deux colonnes, NoteID et labelId, avec un composite PK.
En supposant que vous avez une base de données normalisée, vous devriez avoir une autre table entre notes
et labels
Vous devriez alors utiliser un inner join
pour joindre les tables ensemble
- joindre à la table
labels
avec le bind- Table (many-to-many tableau) - joindre à la table
notes
avec la requête précédente
Exemple:
select * from ((labels l inner join labels_notes ln on l.labelid = ln.labelid) inner join notes n on ln.notesid = n.noteid)
De cette façon, vous avez connecté les deux tables ensemble.
Maintenant, ce que vous devez ajouter est la clause where
... mais je vous laisse le soin de le faire.
Vous ne dites rien sur la façon dont cette relation many-to-many est réalisée. Je suppose que la table des étiquettes a des étiquettes (note: int, label: varchar) - avec une clé primaire couvrant les deux?
SELECT DISTINCT n.id from notes as n, notes_labels as nl WHERE n.id = nl.noteid AND nl.text in (label1, label2);
Remplacez par vos noms de colonnes et insérez les espaces réservés appropriés pour les étiquettes.
Si vous avez juste besoin d'une liste, vous pouvez utiliser where exists
pour éviter les doubles emplois. Si vous avez plusieurs tags par rapport à un nœud dans vos critères de sélection, vous obtiendrez des lignes dupliquées dans le résultat. Voici un exemple 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
Remarque: Je n'ai pas réellement testé cela. Il suppose également que vous avez une table many-to-many nommée notes_labels, ce qui peut ne pas être du tout le cas.
Si vous voulez juste les notes présentant l'une des étiquettes, il est quelque chose comme ceci
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 vous voulez que les notes qui ont toutes les étiquettes, il y a un peu de travail supplémentaire
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;
? être un espace réservé SQL et 2 étant le nombre de tags que vous recherchiez. Cela suppose que la table de liens possède les deux colonnes d'ID en tant que clé primaire composée.
Fait ma journée! Merci ... Merci Google! – fanjabi
Veuillez indiquer le format de votre tableau – JSC
Essayez-vous de sélectionner dynaimquement uniquement les étiquettes utilisées sur plusieurs notes? Si oui, je pense que vous aurez besoin du mot-clé AYANT – Brabster
S'il vous plaît de préciser dans votre question de savoir si vous êtes intéressé par: * Toutes les notes associées à l'étiquette « un » ou « deux » (ou les deux) ou * Seules les notes associées à _both_ étiquettes "un" et "deux". –