MySQL MAX和MIN

时间:2016-05-25 19:41:50

标签: mysql

我正在尝试执行以下查询

SELECT `id`, 
       `name`, 
       `ownerid`, 
       `creationdata`, 
       `motd`, 
       (SELECT Count(*) 
        FROM   guild_membership a, 
               players_online b 
        WHERE  a.player_id = b.player_id 
               AND a.guild_id = id) AS `online`, 
       (SELECT Max(b.level) 
        FROM   guild_membership a, 
               players b 
        WHERE  a.player_id = b.id 
               AND a.guild_id = id) AS `toplevel`, 
       (SELECT Min(a.level) 
        FROM   players a, 
               guild_membership b 
        WHERE  a.id = b.player_id 
               AND b.guild_id = id) AS `lowlevel` 
FROM   `guilds` 
WHERE  `name` = 'Wideswing Poleaxe' 
LIMIT  1; 

此处使用的表格如下:

CREATE TABLE IF NOT EXISTS `players` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `group_id` int(11) NOT NULL DEFAULT '1',
  `account_id` int(11) NOT NULL DEFAULT '0',
  `level` int(11) NOT NULL DEFAULT '1',
  ...
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`),
  FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE,
  KEY `vocation` (`vocation`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `guilds` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `ownerid` int(11) NOT NULL,
  `creationdata` int(11) NOT NULL,
  `motd` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY (`name`),
  UNIQUE KEY (`ownerid`),
  FOREIGN KEY (`ownerid`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `guild_membership` (
  `player_id` int(11) NOT NULL,
  `guild_id` int(11) NOT NULL,
  `rank_id` int(11) NOT NULL,
  `nick` varchar(15) NOT NULL DEFAULT '',
  PRIMARY KEY (`player_id`),
  FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  FOREIGN KEY (`rank_id`) REFERENCES `guild_ranks` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;

我试图在一个公会内的玩家桌上获得最高等级和最低等级

然而,我总是得到更高级别和低级别相同的值,而且总是最低级别

我不确定有什么问题

4 个答案:

答案 0 :(得分:1)

我认为问题在于:a.guild_id = id

正在使用的id来自玩家,而不是公会,因为它仍然是子查询的一部分。

答案 1 :(得分:1)

你不应该需要所有这些子查询,JOIN几乎总是更快,通常应该首先尝试技术。

试试这个......

SELECT `id`, `name`, `ownerid`, `creationdata`, `motd` 
       , COUNT(po.player_id) AS online
       , MAX(p.level) AS toplevel
       , MIN(p.level) AS lowlevel
FROM `guilds` AS g
LEFT JOIN guild_membership AS gm ON g.id = gm.guild_id
LEFT JOIN players AS p ON gm.player_id = p.player_id
LEFT JOIN players_online AS po ON gm.player_id = po.player_id
WHERE g.`name` = 'Wideswing Poleaxe'
;

COUNT仅计算非空值;类似地MAXMIN和大多数其他聚合函数忽略空值(如果仅处理空值,则仅返回null)。

答案 2 :(得分:1)

我注意到的第一件事是:您使用的LIMIT没有ORDER BY。因此,从guilds表中,您希望找到name = 'Wideswing Poleaxe'的多个条目,但只查看DBMS恰好找到的第一个条目。这需要吗?

接下来我看到的是过时的连接语法。你是从哪里得到的?一本二十岁的书?不,停止,二十年前这个语法已经变得多余,所以它必须更老;-)使用显式连接(JOIN ... ON ...

对于您的子查询:您正在与id进行比较而没有任何限定符,因此DBMS将其视为guild_membership.idplayers_onlineplayers.id,您真正想要它guild.id这应该可以解释您会得到意想不到的值。

关于如何构建查询:您可以加入聚合的播放器数据。并使用与表匹配的别名。

select 
  guilds.id, 
  guilds.name, 
  guilds.ownerid, 
  guilds.creationdata, 
  guilds.motd, 
  players.online, 
  players.toplevel, 
  players.lowlevel 
from guilds
left join
(
  select 
    gms.guild_id, 
    max(p.level) as toplevel, 
    min(p.level) as lowlevel, 
    sum((select count(*) from players_online po where po.player_id = p.id)) as online
  from guild_membership gms
  join players p on p.id = gms.player_id
  group by gms.guild_id
) players on players.guild_id = guilds.id
where guilds.name = 'Wideswing Poleaxe';

如果你不需要在没有任何玩家的情况下看到公会,你可以将左外连接(left join)更改为内连接(join)。

答案 3 :(得分:0)

您应该考虑修改您的查询,例如

SELECT g.`id`, 
       g.`name`, 
       g.`ownerid`, 
       g.`creationdata`, 
       g.`motd`, 
       (SELECT Count(*) 
        FROM   guild_membership a, 
               players_online b 
        WHERE  a.player_id = b.player_id 
               AND a.guild_id = id) AS `online`, 
       (SELECT Max(b.level) 
        FROM   players b join guild_membership a on a.player_id = b.id 
               AND a.guild_id = g.id) AS `toplevel`, 
       (SELECT Min(a.level) 
        FROM   players a join 
               guild_membership b on a.id = b.player_id 
               AND b.guild_id = g.id) AS `lowlevel` 
FROM   `guilds` g
WHERE  g.`name` = 'Wideswing Poleaxe' 
LIMIT  1;