First of all you have to build select that select maximal damage for each type (you already have that):
SELECT type, MAX(damage) MaxD FROM Attack GROUP BY Type
Now, this won't have a good performance unless:
- type is
INT
(or ENUM
or other numeric type)
- there's index on
type
or type, damage
You cannot select pokemon_name
because MySQL doesn't guarantee that you'll get pokemon_name
matching MaxD
(here's a nice answer on stackoverflow which already covers this issue).
Now you can select pokemon with that matching 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)
The last GROUP BY
statement makes sure that having multiple pokemons with the same attack damage won't cause multiple records for one type,damage
pairs.
Again, you will achieve good performance by replacing pokemon_name
with pokemon_id
. Maybe you should google database normalization
for a while [wikipedia],[first tutorial]. You also may want to check this Q&A out, it provides nice overview of what does "relation table" mean.
Now you have correct pokemon_name
(for your program sake, I hope you'll replace this with pokemon_id
) and you may put it all together:
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)
Ideal example
In perfect world you're database would look like this:
-- 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 fields are ALWAYS PRIMARY KEY
, NOT NULL
and AUTO_INCREMENT
in this example
And the select from it, again get types first:
SELECT MAX(attack.damage) AS mDmg, attack.typeID
FROM attack
GROUP BY attack.typeID
Than get pokemon 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)
And once you've covered all that you may actually select pokemon data
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
Performance hints:
- you may add field
MaxDamage
into AttackTypes
(which would be calculated by stored procedure) and will save you one level of nasted query
- all
ID
fields should be PRIMARY KEY
s
- index on
Attacks.typeID
allows you to quickly get all pokemons capable of that type of attack
- index on
Attack.damage
allows you to quickly find strongest attack
- index on
Attack.type, Attack.damage
(two fields) will be helpful when finding max value for each attack
- index on
Attack.pokemonID
will make look up pokemon -> attack -> attack type name
faster