查询以获取用户的最新和最高活动

时间:2013-07-31 00:51:10

标签: mysql select join inner-join

我的表格结构如下:

CREATE TABLE `scores` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `nick` VARCHAR(32) NOT NULL,
    `count` SMALLINT(5) UNSIGNED ZEROFILL NOT NULL DEFAULT '00000',
    `messages` SMALLINT(5) UNSIGNED ZEROFILL NOT NULL DEFAULT '00000',
    `dated` DATE NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE INDEX `nick_dated` (`nick`, `dated`),
    INDEX `nick` (`nick`),
    INDEX `count` (`count`),
    INDEX `messages` (`messages`)
)
COMMENT='Chat scores'
COLLATE='utf8_general_ci'
ENGINE=MyISAM;

我希望编写一个查询,以便对于用户输入值nick,我可以生成用户的:

  • 总计数
  • 平均人数
  • 最近一天的计数
  • 最高统计日期

我写的查询是:

SELECT s.`nick` AS `nick`,
    s.`count` AS `recent`,
    t.`total` AS `total`,
    t.`avrg` AS `avrg`,
    MAX(ss.`count`) AS `max`,
    ss.dated
FROM (
    SELECT `nick`,
        SUM(`count`) AS `total`,
        AVG(`count`) AS `avrg`,
        MAX(`dated`) AS `dated` # For most recent activity
    FROM `scores`
    WHERE `nick` = 'hjpotter92'
) AS `t`
INNER JOIN scores s
    ON s.nick = t.nick
        AND s.dated = t.dated
INNER JOIN scores ss
    ON ss.nick = t.nick

我可以选择前三个必需值。但是我怎样才能获得最高活动日期。这是一个sqlfiddle。正如您在小提琴DDL中看到的那样,第24行

INSERT INTO `scores` 
    (`count`, `nick`, `dated`) 
VALUES 
    (00052, 'hjpotter92', '2013-07-29');

计数最高的日期(由MAX(ss.count)正确提取为52)是2013-07-29,但我的选择查询会返回 July, 26 2013

我在哪里做错了?

1 个答案:

答案 0 :(得分:2)

您的查询是一种奇怪的聚合混合。这是一个有效的版本:

SELECT s.`nick` AS `nick`,
    srecent.`count` AS `recent`,
    t.`total` AS `total`,
    t.`avrg` AS `avrg`,
    t.maxcount,
    s.dated
FROM (SELECT `nick`,
             SUM(`count`) AS `total`,
             AVG(`count`) AS `avrg`,
             MAX(`dated`) AS `dated`, # For most recent activity
             max(count) as maxcount
      FROM `scores`
      WHERE `nick` = 'hjpotter92'
      group by nick
     )  `t` INNER JOIN
    scores s
    ON s.nick = t.nick AND
       s.count = t.maxcount join
    scores srecent
    on srecent.nick = t.nick and
       srecent.dated = t.dated;

原始查询的问题是max(count)中的select。这会将外部select转换为聚合查询 - 返回一行。但是,ss上的联接返回了多行,因此从该联接返回了任意行。因此结果不一致。

此版本计算子查询中的各种聚合值。然后它返回到原始表以从那些日期获取其他信息。

制定查询的另一种方法是使用substring_index(group_concat())技巧:

SELECT `nick`,
       substring_index(group_concat(count order by dated desc), ',', 1) as mostrecent,
       SUM(`count`) AS `total`,
       AVG(`count`) AS `avrg`,
       max(count) as maxcount,
       substring_index(group_concat(dated order by count desc), ',', 1) as dated
FROM `scores`
WHERE `nick` = 'hjpotter92'
group by nick;