4

我有一个充满口袋妖怪卡的数据库,以及它们的攻击。我想进行查询以找到每种类型攻击力最强的口袋妖怪。我希望视图只显示攻击的名称、类型和损害。

SELECT p2.MaxD, p2.Type, p1.name 
FROM Pokemon p1 
INNER JOIN ( SELECT type, MAX(damage) MaxD, pokemon_name FROM Attack GROUP BY Type )
p2 ON p1.type = p2.type AND p2.pokemon_name = p1.name

我有这个代码。它返回最高的伤害,但不是正确的口袋妖怪。口袋妖怪表没有伤害字段。我正在尝试了解连接。

这是结构:

攻击表有 4 个字段:pokemon_name(本次攻击所属的宝可梦)、伤害、名称(本次攻击的名称)、类型(本次攻击所属的宝可梦类型)。

口袋妖怪表有 3:HP、类型(口袋妖怪)和名字(口袋妖怪)。

4

2 回答 2

2

首先,您必须构建选择,为每种类型选择最大伤害(您已经有了):

SELECT type, MAX(damage) MaxD FROM Attack GROUP BY Type

现在,除非:

  • 类型是INTENUM或其他数字类型)
  • 有索引typetype, 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 NULLAUTO_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

性能提示:

  • 您可以将字段添加MaxDamageAttackTypes(将由存储过程计算)并为您节省一层嵌套查询
  • 所有ID字段都应该是PRIMARY KEYs
  • index onAttacks.typeID允许您快速获取所有能够进行该类型攻击的口袋妖怪
  • index onAttack.damage让你快速找到最强攻击
  • Attack.type, Attack.damage在找到每次攻击的最大值时,(两个字段)上的索引将很有帮助
  • 索引Attack.pokemonID将使查找pokemon -> attack -> attack type name更快
于 2012-11-11T10:20:07.030 回答
1

我不太确定您的架构,但我认为pokemon_name您的attack表实际上是口袋妖怪的名称。

SELECT  a.*, c.*
FROM    Attack a
        INNER JOIN
        (
            SELECT  type, MAX(damage) MaxD
            FROM Attack 
            GROUP BY Type 
        ) b ON a.Type = b.Type AND
                a.damage = b.MaxD
        INNER JOIN Pokemon c
            ON c.Name = a.pokemon_name AND
                c.Type = a.Type

上面的查询显示了attack表和pokemon表中的所有字段,但是如果你真的对表感兴趣namedamage并且type你只对attack表进行查询

SELECT  a.*
FROM    Attack a
        INNER JOIN
        (
            SELECT  type, MAX(damage) MaxD
            FROM Attack 
            GROUP BY Type 
        ) b ON a.Type = b.Type AND
                a.damage = b.MaxD
于 2012-11-11T10:02:04.743 回答