MySQL计算多个列/表的最大值

时间:2012-10-09 06:19:04

标签: mysql sql

我有一些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

我想要的是为每个标签/主题获取具有最高分的图片或视频,并处理以下边缘情况:

  • 如果给定主题有多个图片或视频(即它们具有相同的高分),则按照资源所有者的分数,如果它们也具有相同的点(不太可能),则两个资源都可以在结果集中(除非资源由同一用户拥有,在这种情况下,结果集中应该只有一个结果)。
  • 如果视频或图片的点数小于20,则从结果集中排除该资源。

作为一个使用Grails的软件开发人员,我喜欢依赖对象关系映射,因此我的sql技能很蹩脚。到目前为止,我能做的最好的事情是将两个选择的结果放在一起:

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');

有关如何最好地提取此信息的任何指示?干杯:)

2 个答案:

答案 0 :(得分: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 JOINsubqueriesUNIONGROUP BY以及GROUP BY基于ORDER BY POINTS DESC将返回第1行的非正式MySQL假设{1}}

答案 1 :(得分:0)

以下是视频查询

select 
    t.content as `TOPIC-ID`,
    vt.video_id as `RESOURCE-ID`,   
    'video' as `RESOURCE-TYPE`,
    vt.owner_id as `RESOURCE-OWNER-ID`,
    vt.MaxPoints

from tags as t
inner join 
    (SELECT 
        vt.tag_id,
        vt.video_id,
        MAX(v.points) as MaxPoints,
        v.id,
        v.owner_id  
    FROM videotags as vt
    left join videos as v on v.id = vt.video_id
    group by vt.tag_id

    ) as vt on vt.tag_id = t.id

union all
SELECT 
    topic_id as `TOPIC-ID`,
    picture_id as `RESOURCE-ID`,
    'picture' as `RESOURCE-TYPE`,
    p.owner_id as `RESOURCE-OWNER-ID`,
    p.points as MaxPoints
FROM picturetopic
LEFT JOIN (SELECT id , owner_id , points FROM pictures) as p on p.id = picturetopic.picture_id