3

いくつかの情報を抽出したい mysql テーブルがいくつかあります。テーブルは次のとおりです。

  • ビデオ - スコア付きのビデオを表します。
  • タグ - タグのグローバル リストが含まれます。
  • VideoTags - ビデオとタグの間の関連付けを作成します。

ビデオ リソースに加えて、写真リソースもあります。

  • 写真 - スコア付きの写真を表します。
  • PictureTopic - 画像とトピックの間の関連付けを作成します。

そして、ビデオと写真の所有権のためのユーザーテーブル

  • ユーザー - ビデオと写真を所有できます

私がやりたいのは、各タグ/トピックで最高のポイントを持つビデオまたは写真を見つけることです. 同じタグ/トピックを持つビデオや画像が多数ありますが、結果セットにはタグ/トピックと同じ数の行が含まれます。最終的な目標は、一意のタグ (ハッシュが前に付いたトピックであるタグ) ごとに (ポイントによる) 最高のビデオまたは写真のリストを作成することです。

前の質問 (http://stackoverflow.com/questions/12778329/mysql-data-extraction-from-3-tables-joins-and-max) の解決策を使用して、最高のビデオをすべて取得できます。各タグのポイント。

SELECT SUBSTR(Tags.content,2) as topic_id, Videos.id as resource_id, 'video' as resource_type, Videos.owner_id as resource_owner_id, Videos.points FROM Videos JOIN (
  SELECT   VideoTags.tag_id, MAX(points) points
  FROM     Videos JOIN VideoTags ON Videos.id = VideoTags.video_id
  GROUP BY VideoTags.tag_id
) t USING (points) JOIN Tags ON t.tag_id = Tags.id and Tags.content LIKE "#%"

また、次の式を使用して、各トピックの最高点の写真を (ちょっと) 取得することもできます。

SELECT   PictureTopic.topic_id, Pictures.id as resource_id, 'picture' as resource_type, Pictures.owner_id as resource_owner_id, MAX(points) points
FROM     Pictures JOIN PictureTopic ON Pictures.id = PictureTopic.picture_id
GROUP BY PictureTopic.topic_id

私が望むのは、次のエッジケースを処理して、各タグ/トピックの最高点を持つ写真またはビデオを取得することです:

  • 特定のトピックに複数の写真またはビデオがある場合 (つまり、それらのスコアが同じである場合)、リソース所有者のポイントに従います。どちらも同じポイントを持っている場合 (可能性は低い)、両方のリソースが結果に含まれる可能性があります。セット (リソースが同じユーザーによって所有されている場合を除きます。この場合、結果セットには 1 つの結果しかないはずです)。
  • ビデオまたは写真のポイントが 20 未満の場合、そのリソースを結果セットから除外します。

Grails を頻繁に使用するソフトウェア開発者として、私はオブジェクト リレーショナル マッピングに頼るのが好きなので、SQL スキルは不十分です。これまでにできる最善のことは、2 つの選択の結果をまとめることです。

SELECT SUBSTR(Tags.content,2) as topic_id, Videos.id as resource_id, 'video' as resource_type, Videos.owner_id as resource_owner_id, Videos.points FROM Videos JOIN (
  SELECT   VideoTags.tag_id, MAX(points) points
  FROM     Videos JOIN VideoTags ON Videos.id = VideoTags.video_id
  GROUP BY VideoTags.tag_id
) t USING (points) JOIN Tags ON t.tag_id = Tags.id and Tags.content LIKE "#%"
UNION
SELECT   PictureTopic.topic_id, Pictures.id as resource_id, 'picture' as resource_type, Pictures.owner_id as resource_owner_id, MAX(points) points
FROM     Pictures JOIN PictureTopic ON Pictures.id = PictureTopic.picture_id
GROUP BY PictureTopic.topic_id

しかし、残念ながら、期待どおりの高得点の写真を取得することさえできません. sqlfiddle でわかるように ( http://sqlfiddle.com/#!2/6650d/1 )

このクエリの出力は次のとおりです。

TOPIC_ID    RESOURCE_ID         RESOURCE_TYPE   RESOURCE_OWNER_ID   POINTS
topic-1     owner-x-video-a     video           owner-x             20
topic-2     owner-y-video-m     video           owner-y             44
topic-1     owner-j-pic-1       picture         owner-j             50
topic-3     owner-k-pic-2       picture         owner-k             22

しかし、私はこの行も期待しています:

TOPIC_ID    RESOURCE_ID         RESOURCE_TYPE   RESOURCE_OWNER_ID   POINTS
topic-3     owner-l-pic-3       picture         owner-l             22

そして、等しいハイスコアとスコアしきい値のエッジケースの後、私は見たいと思います:

TOPIC_ID    RESOURCE_ID         RESOURCE_TYPE   RESOURCE_OWNER_ID   POINTS
topic-1     owner-j-pic-1       picture         owner-j             50
topic-2     owner-y-video-m     video           owner-y             44
topic-3     owner-l-pic-3       picture         owner-l             22

参照用のスキーマとサンプル データは次のとおりです。

CREATE TABLE `Users` (
  `id`       VARCHAR(24) NOT NULL DEFAULT '',
  `points`   DOUBLE      NOT NULL DEFAULT 0,
  PRIMARY KEY (id)
) Engine=InnoDB;

DROP TABLE IF EXISTS `Videos`;
CREATE TABLE `Videos` (
  `id` varchar(24) NOT NULL default '',
  `owner_id` varchar(24) NOT NULL default '',
  `points` DOUBLE NOT NULL default 0
);

DROP TABLE IF EXISTS `Tags`;
CREATE TABLE `Tags` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `content` varchar(32) NOT NULL default ''
PRIMARY KEY (id)
);

DROP TABLE IF EXISTS `VideoTags`;
CREATE TABLE `VideoTags` (
  `video_id` varchar(24) NOT NULL default '',
  `tag_id` int(11) NOT NULL
);

DROP TABLE IF EXISTS `Pictures`;
CREATE TABLE `Pictures` (
  `id` varchar(24) NOT NULL default '',
  `owner_id` varchar(24) NOT NULL default '',
  `points` DOUBLE NOT NULL default 0
);

DROP TABLE IF EXISTS `PictureTopic`;
CREATE TABLE `PictureTopic` (
  `picture_id` varchar(24) NOT NULL,
  `topic_id` varchar(31) NOT NULL
);

INSERT INTO Users (id, points) VALUES ('owner-x', 0);
INSERT INTO Users (id, points) VALUES ('owner-y', 0);
INSERT INTO Users (id, points) VALUES ('owner-j', 0);
INSERT INTO Users (id, points) VALUES ('owner-k', 5);
INSERT INTO Users (id, points) VALUES ('owner-l', 14);

INSERT INTO Videos (id,owner_id,points) VALUES
  ('owner-x-video-a','owner-x', 20),
  ('owner-x-video-b','owner-x', 15),
  ('owner-y-video-k','owner-y', 12),
  ('owner-y-video-l','owner-y', 17),
  ('owner-y-video-m','owner-y', 44);

INSERT INTO Tags (id, content) VALUES
  (111, '#topic-1'),
  (222, '#topic-2');

INSERT INTO VideoTags (video_id,tag_id) VALUES
  ('owner-x-video-a',111),
  ('owner-x-video-b',111),
  ('owner-y-video-k',111),
  ('owner-y-video-l',222),
  ('owner-y-video-m',222);

INSERT INTO Pictures (id, owner_id, points) VALUES ('owner-j-pic-1','owner-j', 50);
INSERT INTO Pictures (id, owner_id, points) VALUES ('owner-k-pic-2','owner-k', 22);
INSERT INTO Pictures (id, owner_id, points) VALUES ('owner-l-pic-3','owner-l', 22);

INSERT INTO PictureTopic (picture_id, topic_id) VALUES ('owner-j-pic-1','topic-1');
INSERT INTO PictureTopic (picture_id, topic_id) VALUES ('owner-k-pic-2','topic-3');
INSERT INTO PictureTopic (picture_id, topic_id) VALUES ('owner-l-pic-3','topic-3');

この情報を最適に抽出する方法についての指針はありますか? 乾杯 :)

4

2 に答える 2

2
SELECT TOPIC_ID, RESOURCE_ID, RESOURCE_TYPE, RESOURCE_OWNER_ID, POINTS
FROM (( SELECT pt.topic_id AS TOPIC_ID,
            p.id AS RESOURCE_ID,
            'picture' AS RESOURCE_TYPE,
            p.owner_id AS RESOURCE_OWNER_ID,
            p.points AS POINTS,
            u.points AS user_points
        FROM Pictures AS p
        INNER JOIN PictureTopic AS pt
        ON p.id = pt.picture_id
        INNER JOIN Users AS u
        ON p.owner_id = u.id)
        UNION ALL
    (   SELECT SUBSTR(t.content, 1), v.id, 'video', v.owner_id, v.points, u.points
        FROM Videos AS v
        INNER JOIN VideoTags AS vt
        ON v.id = vt.video_id
        INNER JOIN Tags AS t
        ON vt.tag_id = t.id
        INNER JOIN Users AS u2
        ON v.owner_id = u2.id)
        ORDER BY POINTS DESC, user_points DESC) AS h
GROUP BY TOPIC_ID
ORDER BY TOPIC_ID ASC

このクエリは、INNER JOINサブクエリUNIONGROUP BYGROUP BY 、およびに基づいて1行目を返す非公式のMySQLの仮定を利用します。ORDER BY POINTS DESC

于 2012-10-09T07:36:13.647 に答える