Question

J'ai une base de données avec deux tables principales notes et labels. Ils entretiennent une relation plusieurs à plusieurs (similaire à la façon dont stackoverflow.com pose des questions avec des étiquettes). Ce que je me demande, c'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 des étiquettes & "; un &"; et " deux " quelle est la requête SQL qui trouvera toutes les notes associées aux étiquettes " un " et & "deux &";

Était-ce utile?

La solution

Pour obtenir le détail des notes comportant les deux labels 'Un' et 'Deux' :

:

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

Autres conseils

Remarque: je n'ai pas encore testé cela. Cela suppose également que vous avez une table plusieurs-à-plusieurs nommée notes_labels, ce qui peut ne pas être le cas du tout.

Si vous voulez juste les notes qui ont une des étiquettes, c'est quelque chose comme ça

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 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 le nombre de balises que vous recherchiez. Cela suppose que la table de liens comporte les deux colonnes ID en tant que clé primaire composée.

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

Bien sûr, remplacez-les par vos noms de colonnes, j'espère que mes hypothèses sur votre table étaient correctes.

Et en réalité, votre question soulève un peu d’ambiguïté grâce à l’anglais et à la façon dont le mot "et" est parfois utilisé. Si vous voulez dire, par exemple, que vous voulez voir une note étiquetée «un» mais pas «deux», cela devrait fonctionner (interpréter vos «et» pour signifier, «affichez-moi toutes les notes avec les étiquettes« un »et / ou toutes les autres les notes avec étiquette «deux»). Toutefois, si vous souhaitez uniquement les notes comportant les deux libellés, ce serait une façon de procéder:

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 de tous, les engrenages du lundi dans mon cerveau sont un peu lents ... on dirait que j'aurais dû le faire par wiki!

Quelque chose comme ça ... (vous aurez besoin d'une autre table de liens)

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

Modifier : la table NoteLabel comportera deux colonnes, noteId et labelId, avec une clé de commande composite.

En supposant que vous ayez 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

  1. Joignez la select * from ((labels l inner join labels_notes ln on l.labelid = ln.labelid) inner join notes n on ln.notesid = n.noteid) table avec la table de liens (table plusieurs-à-plusieurs)
  2. Joindre la where table avec la requête précédente

Exemple:

<=>

Ainsi, vous avez connecté les deux tables ensemble.

Ce que vous devez ajouter, c’est la <=> clause ... mais je vous en laisse la responsabilité.

Vous ne dites rien sur la façon dont cette relation plusieurs à plusieurs est réalisée. Je suppose que la table des étiquettes a des étiquettes (noteid: 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-le par vos noms de colonne 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 doublons. Si vous avez plusieurs balises par rapport à un noeud dans vos critères de sélection, vous obtiendrez des lignes en double dans le résultat. Voici un exemple 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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top