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

私はこのコードを持っています。それは最高のダメージを返しますが、正しいポケモンではありません。ポケモンテーブルにはダメージフィールドがありません。結合を把握しようとしています。

構造は次のとおりです。

攻撃テーブルには、pokemon_name(この攻撃が属するポケモン)、damage、name(攻撃の名前)、およびtype(この攻撃が属するポケモンのタイプ)の4つのフィールドがあります。

ポケモンテーブルには3:HP、タイプ(ポケモンの)、名前(ポケモンの)があります。

4

2 に答える 2

2

まず最初に、各タイプの最大ダメージを選択する select を構築する必要があります (すでに持っています):

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

さて、次の場合を除き、これは良いパフォーマンスを発揮しません。

  • type is INT(またはENUMその他の数値型)
  • typeまたはにインデックスがありますtype, damage

MySQL は一致するpokemon_nameことを保証しないため、選択できません(これは、この問題を既にカバーしている stackoverflow に関する優れた回答です)。pokemon_nameMaxD

これで、その一致するポケモンを選択できます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ステートメントは、同じ攻撃ダメージを持つ複数のポケモンを持っていても、1 つのtype,damageペアに対して複数のレコードが発生しないことを確認します。

繰り返しますが、 に置き換えることpokemon_nameで優れたパフォーマンスが得られpokemon_idます。[ウィキペディア][最初のチュートリアル]database normalizationでしばらくの間、Google で検索する必要があるかもしれません。また、この Q&Aもチェックしてみてください。「リレーション テーブル」の意味を簡単に説明しています。

これで正しいことがわかり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 KEYNOT 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

パフォーマンスのヒント:

  • MaxDamageフィールドを追加してAttackTypes(ストアドプロシージャによって計算されます)、ネストされたクエリの1レベルを節約できます
  • すべてのIDフィールドはPRIMARY KEYsでなければなりません
  • インデックスをオンにAttacks.typeIDすると、そのタイプの攻撃が可能なすべてのポケモンをすばやく取得できます
  • インデックスをオンにAttack.damageすると、最強の攻撃をすばやく見つけることができます
  • (2 つのフィールド) のインデックスは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ますが、本当に興味がある場合は、テーブルに対してnameのみクエリを実行しdamageますtypeattack

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 に答える