4

ここに長い間潜んでいて、このサイトからのアドバイスを何年も使用していて、今私は答えを見つけることができないという質問があります-しかし、解決策は簡単だと確信しています!

音楽トラックのタグ付けシステムを設定しています。私は3つのテーブルを持っています

トラック

---------------
| id | name   |
---------------
| 1  | Track1 |
| 2  | Track2 |
---------------

タグリンク

--------------------------
| id | tag_id | track_id |
--------------------------
| 1  | 1      | 1        | 
| 2  | 2      | 1        | 
| 3  | 2      | 2        |
--------------------------

タグ

-------------------------
| id | tag      | type  |
-------------------------
| 1  | acoustic | genre | 
| 2  | anger    | mood  |
-------------------------

たとえば、tag:acoustic、type:genre AND tag:anger、type:moodなどのトラックのトラック名を取得できるようにしたい。したがって、この場合、両方のタグがあるトラック1が必要です。

私が持っている現在のクエリは

SELECT tracks.name 
FROM tracks
JOIN taglinks ON tracks.id=taglinks.track_id
JOIN tags ON (tags.type='genre' AND tags.tag='acoustic') AND (tags.type='mood' AND tags.tag='anger')
WHERE taglinks.tag_id=tags.id;

これは何も返しません。2番目のJOINでANDセクションを削除すると、すべてのトラックにアコースティックのタグが付けられ、ORに変更すると、両方のトラックが再び期待どおりに取得されます。

ANDを実行して、それらのタグとタイプの両方を持つトラックのみを返すにはどうすればよいですか?

よろしくお願いします:D

編集:

私が何を求めているのかを明確にするためだけに。AcousticとAngerの両方をタグとして持つトラックを取得できるようにしたいのですが、それらのタグが指定されたタイプにも一致する場合に限ります。

これは、後でタイプジャンルのジャズというタグとタイプスタイルのジャズというタグが作成される可能性があり、タグ自体だけでなく、正しいタイプのタグで選択していることを確認できる必要があるためです。

これが私が使っているsqlfiddleへのリンクです-http://sqlfiddle.com/#!2/aad82/ 3

Gillesの答えは、これまでのところ良い解決策のようです。

4

3 に答える 3

2

これは大丈夫です

select
t.name
from
tracks as t 
inner join taglinks as tl on t.id = tl.track_id
inner join tags as tg on tl.tag_id = tg.id
where
tg.tag = 'acoustic' and
tg.type = 'genre' and 
tg.tag = 'anger' and
tg.type = 'mood';

注:as identifierテーブル名をどこにでも書く手間が省けるので、私はそれを好きなように使用しています。あなたはする必要はありません。

編集

私はあなたの質問を少し誤解したかもしれないので、これも役立つかもしれません:

select
t.name
from
tracks as t 
inner join taglinks as tl on t.id = tl.track_id
inner join tags as tg on tl.tag_id = tg.id
where
(tg.tag = 'acoustic' and
tg.type = 'genre') or 
(tg.tag = 'anger' and
tg.type = 'mood');

これにより、正しいタイプANDタグを持つ結果が返されますが、すべてを持っている必要はありません。

于 2012-12-13T15:26:26.857 に答える
1

問題は、トラックに2つのタグが要求された値と等しい必要があることです。まだ投稿されたすべての要求は、その状況では機能しません。INTERSECT sqlコマンドを使用する必要がありますが、これはmysqlでは使用できません。

そのようなものが機能するはずです:

SELECT tracks.id, tracks.name
FROM  `taglinks` 
LEFT JOIN tags ON tags.id = taglinks.tag_id
LEFT JOIN tracks ON tracks.id = taglinks.track_id
WHERE (
tag =  'accoustic'
AND `type` =  'genre'
)
OR (
tag =  'anger'
AND `type`=  'mood'
)
GROUP BY track_id
HAVING COUNT( * ) =2
  • 少なくとも1つのタグに一致するすべての行を選択します
  • と一致するタゲの数を数えますGROUP BY
  • 2つのパラメーターを検索すると(ここaccoustic = 'genre'anger = 'mood'、このトラックの2つの行が見つかりました)、2つの条件に一致し、最終結果に保持されます
  • HAVING COUNT( * ) =2検索するタグの数で変更することを忘れないでください
于 2012-12-13T16:37:16.080 に答える
1
SELECT * FROM tracks tracks
INNER JOIN
(SELECT taglinks.track_id, COUNT(*) as cnt
FROM tags tags
INNER JOIN taglinks taglinks ON taglinks.tag_id = tags.id
WHERE
    (tags.tag='ac' AND tags.type='ge')
    OR (tags.tag='an' AND tags.type='mo')
GROUP BY taglinks.track_id
)AS track_match
    ON track_match.track_id = tracks.id AND track_match.cnt = 2

「track_match.cnt=2」を置き換える必要があります2=一致する条件の数

このソリューションにはある程度の柔軟性があります。最小数の条件が満たされているトラックを作成することもできます。

たとえば、ここでは、track_match.cnt> = 1を追加し、またORDER BYtrack_match.cntDESCを追加できます。

一致した条件の数順に並べられたトラックのリストを取得します。

于 2012-12-13T17:29:33.997 に答える