6

次の表を検討してください。

[Table: talks]
talkID | title        | starred
-------+--------------+--------
1      | talk1-title  | 1
2      | talk2-title  | 1
3      | talk3-title  | 0
4      | talk4-title  | 0
5      | talk5-title  | 0

[Table: talkspeaker]
talkID | speaker
-------+---------
1      | Speaker1
1      | Speaker2
2      | Speaker3
3      | Speaker4
3      | Speaker5
4      | Speaker6
5      | Speaker7
5      | Speaker8

[Table: similartalks]
talkID | similarTo
-------+----------
1      | 3
1      | 4
2      | 3
2      | 4
2      | 5
3      | 2
4      | 5
5      | 3
5      | 4

私がやりたいことは次のとおりです。スター付きトークのセットが与えられた場合、スターなしのトーク (スター付き = 0) の上位 2 つと、スター付きトークのセットに最も類似したタイトルとスピーカーを選択したいと思います。問題は、講演者を取得するには集計関数を使用する必要があり、最も類似した講演を取得する必要があることです。

論争にスピーカーがいなくても、次のクエリを使用して、最も類似した講演を得ることができました。

select t2.talkID, t2.title, count(*) as count 
from similarTalks s, talks t1, talks t2
where s.talkID = t1.talkID
and t1.Starred = 1
and s.similarTo = t2.TalkID
and t2.Starred = 0
group by t2.title, t2.talkID
order by count desc
limit 2

一般的に、スピーカーを取得するために次の集計関数を使用し、適切なグループごとの列 (t = talkspeaker と仮定) を使用します。

group_concat(t.speaker, ', ') as Speakers

のように

select t1.title, group_concat(t2.speaker, ', ') as Speakers 
from talks t1, talkspeaker t2
where t1.talkID = t2.talkID
group by t1.title

しかし、私は2つのことを一緒に組み合わせることができません。このクエリを sqlite データベースで実行することを計画していることが問題になる場合があります (これが group_concat 関数の由来です)。スター付きトークに最も類似したトップ 2 のスターなしトークへの回答は、talkID 3 と 4 のようです。

4

2 に答える 2

6

最初に、上記の古い ANSI 89 の代わりに ANSI 92 Join を使用する理由について、この記事を読むことをお勧めします。次に、SQLLite は GROUP_CONCAT 関数をサポートしているため、これを使用できます。

目的の結果を得るには、2 番目のクエリをサブクエリとして最初のクエリに追加するだけです。

SELECT  Talks.TalkID, 
        Talks.Title, 
        ts.Speakers, 
        COUNT(*) AS SimilarTalks
FROM    Talks
        INNER JOIN SimilarTalks 
            ON Talks.TalkID = SimilarTalks.SimilarTo
        INNER JOIN Talks t2
            ON SimilarTalks.TalkID = t2.TalkID
            AND t2.Starred = 1
        INNER JOIN
        (   SELECT  TalkID, GROUP_CONCAT(Speaker, ',') AS Speakers
            FROM    TalkSpeaker
            GROUP BY TalkID
        ) ts
            ON ts.TalkID = Talks.TalkID
WHERE   Talks.Starred = 0
GROUP BY Talks.TalkID, Talks.Title, ts.Speakers
ORDER BY COUNT(*) DESC
LIMIT 2;

SQL Fiddle の例

編集

次を使用して、サブクエリなしでこれを行うこともできますDISTINCT

SELECT  Talks.TalkID, 
        Talks.Title, 
        GROUP_CONCAT(DISTINCT ts.Speaker) AS Speakers,
        COUNT(DISTINCT t2.TalkID) AS SimilarTalks
FROM    Talks
        INNER JOIN SimilarTalks 
            ON Talks.TalkID = SimilarTalks.SimilarTo
        INNER JOIN Talks t2
            ON SimilarTalks.TalkID = t2.TalkID
            AND t2.Starred = 1
        INNER JOIN TalkSpeaker ts
            ON ts.TalkID = Talks.TalkID
WHERE   Talks.Starred = 0
GROUP BY Talks.TalkID, Talks.Title
ORDER BY COUNT(DISTINCT t2.TalkID) DESC
LIMIT 2;

ただし、この方法にはまったく利点がなく、効率が低下する可能性があります(テストしていないため、確実ではありません)

于 2013-01-23T08:54:10.653 に答える
3

まず、目的のトークのIDだけを取得するには、最初のクエリから他のフィールドを削除します。

SELECT unstarred.talkID
FROM talks AS starred
  JOIN similarTalks AS s ON starred.talkID = s.talkID
  JOIN talks AS unstarred ON s.similarTo = unstarred.talkID
WHERE starred.starred
  AND NOT unstarred.starred
GROUP BY unstarred.talkID
ORDER BY COUNT(*) DESC
LIMIT 2

次に、これをサブクエリとして使用して、目的のトークに関する情報を取得します。

SELECT t.title AS Title,
       group_concat(s.speaker, ', ') AS Speakers
FROM talks AS t JOIN talkspeaker AS s ON t.talkID = s.talkID
WHERE t.talkID IN (SELECT unstarred.talkID
                   FROM talks AS starred
                     JOIN similarTalks AS s ON starred.talkID = s.talkID
                     JOIN talks AS unstarred ON s.similarTo = unstarred.talkID
                   WHERE starred.starred
                     AND NOT unstarred.starred
                   GROUP BY unstarred.talkID
                   ORDER BY COUNT(*) DESC
                   LIMIT 2)
GROUP BY t.talkID
于 2013-01-23T08:46:53.453 に答える