首先,您必须构建选择,为每种类型选择最大伤害(您已经有了):
SELECT type, MAX(damage) MaxD FROM Attack GROUP BY Type
现在,除非:
- 类型是
INT
(ENUM
或其他数字类型)
- 有索引
type
或type, damage
您不能选择pokemon_name
,因为 MySQL 不保证您会得到pokemon_name
匹配MaxD
(这里是关于 stackoverflow 的一个很好的答案,它已经涵盖了这个问题)。
现在您可以选择具有该匹配的口袋妖怪pokemon_name
SELECT p1.pokemon_name, p1.type, p1.damage
FROM Attack p1
INNER JOIN (
SELECT type, MAX(damage) MaxD FROM Attack GROUP BY Type
) p2 ON p1.type = p2.type
AND p1.damage = p2.MaxDamage
GROUP BY (p1.type, p1.damage)
最后一条GROUP BY
语句确保拥有多个具有相同攻击伤害的口袋妖怪不会导致一对多记录type,damage
。
同样,您将通过替换为 来获得良好的pokemon_name
性能pokemon_id
。也许你应该谷歌database normalization
一段时间[wikipedia],[first tutorial]。您可能还想查看此问答,它很好地概述了“关系表”的含义。
现在您有正确pokemon_name
的(为了您的程序,我希望您将其替换为pokemon_id
),您可以将它们放在一起:
SELECT p1.pokemon_name, p1.type, p1.damage, p.*
FROM Attack p1
INNER JOIN (
SELECT type, MAX(damage) MaxD FROM Attack GROUP BY Type
) p2 ON p1.type = p2.type
AND p1.damage = p2.MaxDamage
INNER JOIN Pokemon p
ON p.pokemon_name = p1.pokemon_name
GROUP BY (p1.type, p1.damage)
理想的例子
在完美世界中,您的数据库将如下所示:
-- Table with pokemons
CREATE TABLE `pokemons` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255),
-- More fields
PRIMARY KEY (`id`)
)
-- This contains pairs as (1,'Wather'), (2, 'Flame'), ...
CREATE TABLE `AttackTypes` (
`id`,
`name` VARCHAR(255)
)
-- Create records like (1, 2, 3, 152)
-- 1 = automatically generated keys
-- 2 = id of pokemon (let say it's Pikachu :P)
-- 3 = type of attack (this say it's Electric)
-- 152 = damage
-- This way each pokemon may have multiple attack types (Charizard flame + wind)
CREATE TABLE `Attacks` (
`id`,
`pokemonID` INT NOT NULL, -- Represents pokemons.id
`typeID` INT NOT NULL, -- Represents attack.id
`damage` INT
)
ID 字段是ALWAYS PRIMARY KEY
,在这个例子NOT NULL
中AUTO_INCREMENT
然后从中选择,再次首先获取类型:
SELECT MAX(attack.damage) AS mDmg, attack.typeID
FROM attack
GROUP BY attack.typeID
比获得口袋妖怪ID:
SELECT a.pokemonID, a.damage, a.typeID
FROM attack AS a
INNER JOIN (
SELECT MAX(a.damage) AS mDmg, a.typeID
FROM attack AS a
GROUP BY a.typeID
) AS maxA
ON a.typeID = maxA.typeID
AND a.damage = mDmg
GROUP BY (a.typeID)
一旦你涵盖了所有内容,你实际上可能会选择口袋妖怪数据
SELECT aMax.pokemonID as id,
aMax.damage,
p.name AS pokemonName,
aMax.typeID AS attackTypeID,
t.name AS attackType
FROM (
SELECT a.pokemonID, a.damage, a.type
FROM attack AS a
INNER JOIN (
SELECT MAX(a.damage) AS mDmg, a.type
FROM attack AS a
GROUP BY a.type
) AS maxA
ON a.type = maxA.type
AND a.damage = mDmg
GROUP BY (a.type)
) AS aMax
INNER JOIN pokemons AS p
ON p.id = aMax.pokemonID
INNER JOIN AttackTypes AS t
ON t.id = aMax.typeID
性能提示:
- 您可以将字段添加
MaxDamage
到AttackTypes
(将由存储过程计算)并为您节省一层嵌套查询
- 所有
ID
字段都应该是PRIMARY KEY
s
- index on
Attacks.typeID
允许您快速获取所有能够进行该类型攻击的口袋妖怪
- index on
Attack.damage
让你快速找到最强攻击
Attack.type, Attack.damage
在找到每次攻击的最大值时,(两个字段)上的索引将很有帮助
- 索引
Attack.pokemonID
将使查找pokemon -> attack -> attack type name
更快