0

もう一度、私の小さなデータベースでmysqlについて練習するための質問:

私は次のようにテーブルを手に入れました:

Songs       Link        Tags
=======     =====       =======
Sid          Sid        Tid
Songname     Tid        Tagname

今私がやろうとしているのは、いくつかのタグを入力して曲をクエリ(または検索)して、その曲が一致率を作成するために必要なタグの数を表示することです。

素晴らしいstackoverflowコミュニティのおかげで私はクエリを受け取りました

SELECT s.Sid, s.Songname
FROM Songs s
JOIN Link l ON ( l.Sid = s.Sid )
JOIN Tags t ON ( t.Tid = s.Tid )
WHERE t.Tagname IN ( 'X', 'Y' )
GROUP BY s.Sid, s.Songname
HAVING COUNT(1) = 2

これらの2つのタグに完全に一致する曲を検索します。
ここで、タグG、X、Y、およびZを持つこの曲Aがあるとします
。クエリには、XとYが含まれているため、この曲が見つかります。ただし、この曲には他に2つあるので、この曲の50%を示す一致率を(phpを使用して)作成します。

PHPの部分に問題はありませんが、これらのタグに一致するすべての曲と、1つの結果セット内のタグの総数を取得するためのクエリを理解できません。

乾杯!

編集1:


ほとんどの答えが私がすでに試したことを示していることに気づきました。だから私は別のより深い例を作ります:
あなたが次の4つの曲を持っていると仮定します:

タグA、B、X、Y
のAタグA、B、C、D、E、X、YC
のタグA 、B、C、D、F、X
D、タグXおよびY

ここで、タグXおよびYを持つ曲を検索するためのクエリが入力されます。次の出力が必要です。

TotalNumberOfTags:    Song:
4                      A
7                      B
2                      D

CはXとYを持っていなかったので、彼は脱落します。

Edit2:


説明のために、クエリを使用したい

SELECT COUNT(t.Tagname) FROM FROM Songs s 
JOIN Link l ON ( l.Sid = s.Sid ) 
JOIN Tags t ON ( t.Tid = s.Tid ) 
WHERE s.Songname="A"

上記のクエリによって引き起こされた曲名のセット全体で、セットでORDER BY COUNT(t.Tagname)ASCを使用する1つのクエリ。

4

3 に答える 3

0

私が見つけた答えは回避策ですが、それは機能します。このような一時テーブルを作成します

CREATE TEMPORARY TABLE numberoftags ( songname VARCHAR(50) NOT NULL, numberoftags INT);

質問に表示した2つの別々のクエリを入力します。
次に、簡単なクエリで

SELECT * FROM numberoftags ORDER BY numberoftags DESC

タグの総数が付いたすべての曲を受け取り、1つずつ表示します。PHPで接続を閉じると、この一時テーブルは自動的に削除されるので、面倒なことはありません。

于 2012-06-11T18:39:09.360 に答える
0

次のようなものを使用して、各グループ(つまり、各曲)のレコード数をカウントすることによってもカウントを取得できると思います...

SELECT s.Sid, s.Songname, COUNT(t.Tagname)
FROM Songs s
JOIN Link l ON ( l.Sid = s.Sid )
JOIN Tags t ON ( t.Tid = s.Tid ) AND t.Tagname IN ( 'X', 'Y' )
GROUP BY s.Sid, s.Songname;

また、タグ名を含む単一の文字列を送信してから、Find_In_Setを使用する方が簡単な場合があります

SELECT s.Sid, s.Songname, COUNT(t.Tagname)
FROM Songs s
JOIN Link l ON ( l.Sid = s.Sid )
JOIN Tags t ON ( t.Tid = s.Tid ) AND FIND_IN_SET(t.Tagname,"G,X,Y,Z")>0
GROUP BY s.Sid, s.Songname;

検索に使用したタグ名のリストは動的な要素だと思っていたので、明らかに理解できませんでした。内部クエリを使用して検索条件(「X」、「Y」など)に一致する曲を取得してから、外部クエリを使用して各曲のタグ数を取得できると思います。

select COUNT(to.Tagname), so.Songname FROM FROM Songs so 
JOIN Link lo ON ( lo.Sid = so.Sid ) 
JOIN Tags to ON ( to.Tid = so.Tid ) 
WHERE so.SongName in
   ( SELECT si.SongName
      FROM Songs si
      JOIN Link li ON ( li.Sid = si.Sid )
      JOIN Tags ti ON ( ti.Tid = si.Tid )
      WHERE ti.Tagname IN ( 'X', 'Y' )
      GROUP BY si.Sid, si.Songname
      HAVING COUNT(1) = 2
   )
order by COUNT(to.Tagname);
于 2012-06-10T12:13:01.643 に答える
0

HAVING句を削除します-それが必要だとは思わないでください。COUNT(l.Sid) AS MatchedTagsSELECTステートメントを追加します。

SELECT s.Sid, s.Songname, COUNT(l.Sid) AS MatchedTags
FROM Songs s
JOIN Link l ON ( l.Sid = s.Sid )
JOIN Tags t ON ( t.Tid = s.Tid )
WHERE t.Tagname IN ( 'X', 'Y' )
GROUP BY s.Sid, s.Songname
HAVING COUNT(1) = 2

また、個人的な意見によるものですが、原則として、多対多の関係にある「リンク」テーブルには、関係する2つのテーブル名の組み合わせとして名前を付けます。たとえば、Song、Tag、およびミドルテーブルSongTagがあります。

そして、可能な限り頭字語を常に避けてください!各テーブルの主キー列は単にIdと呼ぶことができ、SongTagテーブル(またはLinkテーブル)にはsidとtidではなくSongIdとTagIdが含まれます。

必要に応じてHAVING COUNT(1) = 2、(1)を変更して、読みやすくするために実際に列名を参照するようにします。

悪い習慣ですが、これも私の個人的な意見です。

私のクエリは次のようになりました:(2曲と5タグ付き)。

SELECT 
    s.Id, 
    s.Name,
    COUNT(st.Id) AS MatchedTags
FROM 
    SongTag st
        INNER JOIN Song s ON st.SongId = s.Id
        INNER JOIN Tag t ON st.TagId = t.Id
WHERE 
    t.Name IN ('Tag2', 'Tag3', 'Tag4', 'Tag5')
GROUP BY
    s.Id,
    s.Name
于 2012-06-10T12:14:07.223 に答える