Вопрос

У меня есть база данных с двумя основными таблицами notes и labels.У них есть отношения "многие ко многим" (аналогично тому, как stackoverflow.com имеет вопросы с ярлыками).Что мне интересно, так это как я могу выполнить поиск заметки, используя несколько меток, используя SQL?

Например, если у меня есть заметка "test" с тремя метками "one", "two" и "three", и у меня есть вторая заметка "test2" с метками "one" и "two", какой SQL-запрос найдет все заметки, связанные с метками "one" и "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'
)

Другие советы

Примечание:На самом деле я этого не тестировал.Это также предполагает, что у вас есть таблица "многие ко многим" с именем notes_labels, что может быть совсем не так.

Если вы просто хотите, чтобы заметки имели какой-либо из ярлыков, это должно быть что-то вроде этого

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

Если вам нужны заметки со ВСЕМИ надписями, потребуется небольшая дополнительная работа

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;

?является заполнителем SQL, а 2 - количеством тегов, которые вы искали.Это предполагает, что таблица ссылок содержит оба столбца идентификаторов в качестве составного первичного ключа.

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

Конечно, замените ваши фактические названия столбцов, надеюсь, мои предположения о вашей таблице были правильными.

И на самом деле в вашем вопросе есть некоторая двусмысленность благодаря английскому языку и тому, как иногда используется слово "и".Если вы имеете в виду, что хотите увидеть, например, заметку с пометкой "один", но не "два", это должно сработать (интерпретируя ваши "и" как означающие "покажите мне все заметки с пометкой "один" и / или все заметки с пометкой "два").Однако, если вам нужны только заметки с обоими метками, это был бы один из способов добиться этого:

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

Редактировать:спасибо всем за предложения, шестеренки понедельника в моем мозгу немного тормозят ... Похоже, я должен был сделать это вики!

Что-то вроде этого...(вам понадобится еще одна таблица ссылок)

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

Редактировать:таблица NoteLabel будет содержать два столбца, NoteID и labelId, с составным PK.

Предполагая, что у вас есть нормализованная база данных, у вас должна быть еще одна промежуточная таблица notes и labels

Затем вы должны использовать inner join чтобы соединить таблицы вместе

  1. Присоединяйтесь к labels таблица с таблицей привязки (таблица "многие ко многим")
  2. Присоединяйтесь к notes таблица с предыдущим запросом

Пример:

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

Таким образом, вы соединили обе таблицы вместе.

Теперь то, что вам нужно добавить, это where оговорка ... Но я оставляю это на ваше усмотрение.

Вы ничего не говорите о том, как реализуются эти отношения "многие ко многим".Я предполагаю, что в таблице labels есть метки is(noteid:int, метка:varchar) - с первичным ключом, охватывающим оба?

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

Замените их вашими названиями столбцов и вставьте соответствующие заполнители для меток.

Если вам просто нужен список, вы можете использовать where exists чтобы избежать дублирования.Если у вас есть несколько тегов для узла в ваших критериях выбора, вы получите повторяющиеся строки в результате.Вот пример того, как 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top