0

私は3つのテーブルを持っています:

actor

|    FIELD |             TYPE | NULL | KEY | DEFAULT |          EXTRA |
|----------|------------------|------|-----|---------|----------------|
| actor_id | int(10) unsigned |   NO | PRI |  (null) | auto_increment |
| username |      varchar(30) |   NO |     |  (null) |                |


tag
|  FIELD |             TYPE | NULL | KEY | DEFAULT |          EXTRA |
|--------|------------------|------|-----|---------|----------------|
| tag_id | int(10) unsigned |   NO | PRI |  (null) | auto_increment |
|  title |      varchar(40) |   NO |     |  (null) |                |

actor_tag_count
|            FIELD |             TYPE | NULL | KEY |           DEFAULT |                       EXTRA |
|------------------|------------------|------|-----|-------------------|-----------------------------|
|         actor_id | int(10) unsigned |   NO | PRI |            (null) |                             |
|           tag_id | int(10) unsigned |   NO | PRI |            (null) |                             |
|       clip_count | int(10) unsigned |   NO |     |            (null) |                             |
| update_timestamp |        timestamp |   NO |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |

SQLフィドル

各アクター の 5 つの最も頻繁な (highest ) タグとclip_count最近更新された (latest ) タグを取得したいと考えています。update_timestamp

私の試みたクエリは次のとおりです。

SELECT
    `a`.`actor_id`,
    `a`.`username`,
    GROUP_CONCAT(atc.clip_count) AS `tag_clip_counts`,
    GROUP_CONCAT(t.tag_id) AS `tag_ids`,
    GROUP_CONCAT(t.title) AS `tag_titles`
FROM
    `actor` AS `a`
LEFT JOIN (
    SELECT
        `atc`.`actor_id`,
        `atc`.`tag_id`,
        `atc`.`clip_count`
    FROM
        `actor_tag_count` AS `atc`
    INNER JOIN `actor` AS `a` USING (actor_id)
    ORDER BY
        atc.clip_count DESC,
        atc.update_timestamp DESC
    LIMIT 5
) AS `atc` USING (actor_id)
LEFT JOIN `tag` AS `t` ON atc.tag_id = t.tag_id
GROUP BY
    `a`.`actor_id`

問題は、左側の結合副選択が 1 回だけ計算され、セット内のすべての結果のタグが 5 つのタグのプールからのみフェッチされることです。

GROUP_CONCATキアヌ・リーブスの予想されるタグタイトルの結果:

comedy, scifi, action, suspense, western (西部劇もドキュメンタリーもclip_count2 の がwesternありますが、後の があるので最初に来る必要がありますupdate_timestamp)

これが関連性のあるポイントであるかどうかはわかりませんが、アクターテーブルで他の結合を実行していますが、この質問のためにそれらを削除しました. これをすべて1つのクエリにすることが非常に望ましいですが、2つのクエリでもこれを行う方法に困惑しています。1 つまたは 2 つのクエリ ソリューションを歓迎します。

4

2 に答える 2

1

SQLFiddle 、 GROUP_CONCAT 制限の回避策の使用に関する非常に素晴らしい回答の助けを借りて:

SELECT
    `a`.`actor_id`,
    `a`.`username`,
    SUBSTRING_INDEX(GROUP_CONCAT(atc.clip_count ORDER BY atc.clip_count DESC, atc.update_timestamp DESC), ',', 5) AS `tag_clip_counts`,
    SUBSTRING_INDEX(GROUP_CONCAT(t.tag_id ORDER BY atc.clip_count DESC, atc.update_timestamp DESC), ',', 5) AS `tag_ids`,
    SUBSTRING_INDEX(GROUP_CONCAT(t.title ORDER BY atc.clip_count DESC, atc.update_timestamp DESC), ',', 5) AS `tag_titles`
FROM
    `actor` AS `a`
LEFT JOIN actor_tag_count AS `atc` USING (actor_id)
LEFT JOIN `tag` AS `t` ON atc.tag_id = t.tag_id
GROUP BY
    `a`.`actor_id`
于 2013-10-27T14:00:10.273 に答える
0

シーケンス番号を追加することで可能ですが、大きなテーブルではうまく機能しない可能性があります。

このようなもの(テストされていません):-

    SELECT actor_id,
        username,
        GROUP_CONCAT(clip_count) AS tag_clip_counts,
        GROUP_CONCAT(tag_id) AS tag_ids,
        GROUP_CONCAT(title) AS tag_titles
    FROM
    (
    SELECT  actor.actor_id,
            actor.username,
            atc.clip_count, 
            tag.tag_id,
            tag.title,
            @aSeq := IF(@aActorId = actor.actor_id, @aSeq, 0) + a AS aSequence,
            @aActorId := actor.actor_id
    FROM
    (
        SELECT actor.actor_id,
            actor.username,
            atc.clip_count, 
            tag.tag_id,
            tag.title
        FROM actor
        LEFT JOIN actor_tag_count AS atc ON actor.actor_id = atc.actor_id
        LEFT JOIN tag ON atc.tag_id = tag.tag_id
        ORDER BY actor.actor_id, atc.clip_count DESC, atc.update_timestamp DESC
    )
    CROSS JOIN (SELECT @aSeq:=0, @aActorId:=0)
    )
    WHERE aSequence <= 5
    GROUP BY actor_id, username

別の方法としては、select ステートメントに相関サブクエリを含むサブセレクトを作成し (制限は 5)、グループ連結を実行する外部クエリを作成することもできます。このようなもの(これもテストされていません)

SELECT
    actor_id,
    username,
    GROUP_CONCAT(clip_count) AS tag_clip_counts,
    GROUP_CONCAT(tag_id) AS tag_ids,
    GROUP_CONCAT(title) AS tag_titles
FROM
(
SELECT
    a.actor_id,
    a.username,
    (
    SELECT
        atc.clip_count,
        t.tag_id,
        t.title
    FROM actor_tag_count AS atc ON a.actor_id = atc.actor_id
    LEFT JOIN tag t ON atc.tag_id = t.tag_id
    ORDER BY atc.clip_count DESC, atc.update_timestamp DESC
    LIMIT 5
)
FROM actor a
)
GROUP BY actor_id, username
于 2013-10-27T12:40:11.427 に答える