6

2つのメインテーブルnotesとを含むデータベースがありますlabels。それらは多対多の関係を持っています(stackoverflow.comがラベルに関する質問をする方法と同様です)。私が疑問に思っているのは、SQLを使用して複数のラベルを使用してメモを検索するにはどうすればよいですか?

たとえば、「1」、「2」、「3」の3つのラベルが付いた「test」というメモがあり、「1」と「2」というラベルが付いた2番目のメモ「test2」がある場合、SQLクエリは何になりますか。ラベル「1」と「2」に関連付けられているすべてのメモを検索しますか?

4

7 に答える 7

8

「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'
)
于 2008-12-08T13:44:24.830 に答える
1
select * from notes a
inner join notes_labels mm on (mm.note = a.id and mm.labeltext in ('one', 'two') )

もちろん、実際の列名に置き換えてください。テーブルに関する私の仮定が正しいことを願っています。

実際、英語のおかげで、質問には多少のあいまいさがあり、「および」という単語が時々どのように使用されるかがわかります。たとえば、「1」とタグ付けされているが「2」とタグ付けされていないメモを見たい場合は、これでうまくいくはずです(「と」を意味するように解釈すると、「1」というラベルの付いたすべてのメモを表示します。ラベル「two」のメモ)。ただし、両方のラベルが付いたメモのみが必要な場合は、これが1つの方法です。

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

編集:みんなの提案に感謝します、私の脳の月曜日のギアは少し遅いです...私はそれをウィキするべきだったようです!

于 2008-12-08T13:36:26.437 に答える
1

注:私は実際にこれをテストしていません。また、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 は検索していたタグの数です。これは、リンク テーブルに両方の ID 列が複合主キーとして含まれていることを前提としています。

于 2008-12-08T14:12:34.477 に答える
0

このようなもの...(別のリンクテーブルが必要になります)

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

編集: NoteLabel テーブルには、複合 PK を持つ noteId と labelId の 2 つの列があります。

于 2008-12-08T13:37:26.683 に答える
0

notes正規化されたデータベースがあると仮定すると、 と の間に別のテーブルが必要です。labels

次に、を使用しinner joinてテーブルを結合する必要があります

  1. labelsbind-table (多対多テーブル) でテーブルを結合します。
  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句です...しかし、それはあなたに任せます。

于 2008-12-08T13:40:39.283 に答える
0

この多対多の関係がどのように実現されているかについては何も言いません。ラベル テーブルが Labels(noteid: int, label: varchar) であると仮定します-主キーが両方にまたがっていますか?

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

を列名に置き換え、ラベルの適切なプレースホルダーを挿入します。

于 2008-12-08T13:41:38.750 に答える
0

リストだけが必要な場合は、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
于 2008-12-08T13:52:44.297 に答える