我正在尝试执行以下查询
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;
我试图在一个公会内的玩家桌上获得最高等级和最低等级
然而,我总是得到更高级别和低级别相同的值,而且总是最低级别
我不确定有什么问题
答案 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
仅计算非空值;类似地MAX
,MIN
和大多数其他聚合函数忽略空值(如果仅处理空值,则仅返回null)。
答案 2 :(得分:1)
我注意到的第一件事是:您使用的LIMIT
没有ORDER BY
。因此,从guilds表中,您希望找到name = 'Wideswing Poleaxe'
的多个条目,但只查看DBMS恰好找到的第一个条目。这需要吗?
接下来我看到的是过时的连接语法。你是从哪里得到的?一本二十岁的书?不,停止,二十年前这个语法已经变得多余,所以它必须更老;-)使用显式连接(JOIN ... ON ...
)
对于您的子查询:您正在与id
进行比较而没有任何限定符,因此DBMS将其视为guild_membership.id
或players_online
。 players.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;