Documentation Home
MySQL 8.0 リファレンスマニュアル
Download this Manual
PDF (US Ltr) - 36.1Mb
PDF (A4) - 36.2Mb


MySQL 8.0 リファレンスマニュアル  /  ...  /  機能依存性の検出

このページは機械翻訳したものです。

12.20.4 機能依存性の検出

次の説明では、MySQL が関数従属性を検出する方法の例をいくつか示します。 この例では、次の表記法を使用します:

{X} -> {Y}

これをX は、Y を一意に決定」として理解します。つまり、Y は機能的に X に依存しています。

この例では、https://dev.mysql.com/doc/index-other.html からダウンロードできる world データベースを使用します。 データベースのインストール方法の詳細は、同じページを参照してください。

キーから導出された関数従属性

次のクエリーは、国ごとに話された言語の数を選択します:

SELECT co.Name, COUNT(*)
FROM countrylanguage cl, country co
WHERE cl.CountryCode = co.Code
GROUP BY co.Code;

co.Codeco の主キーであるため、次の表記法を使用して表されるように、co のすべてのカラムは機能的に依存します:

{co.Code} -> {co.*}

したがって、co.name は機能的に GROUP BY カラムに依存し、クエリーは有効です。

主キーのかわりに NOT NULL カラムに対する UNIQUE インデックスを使用でき、同じ機能依存性が適用されます。 (複数の NULL 値が許可され、その場合は一意性が失われるため、NULL 値を許可する UNIQUE インデックスには当てはまりません。)

複数カラムキーおよび等価から導出された関数従属性

このクエリーでは、国ごとに、すべての話し言葉のリストとそれらを話すユーザーの数を選択します:

SELECT co.Name, cl.Language,
cl.Percentage * co.Population / 100.0 AS SpokenBy
FROM countrylanguage cl, country co
WHERE cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

ペア (cl.CountryCodecl.Language) は cl の 2 カラム複合主キーであるため、カラムのペアによって cl のすべてのカラムが一意に決定されます:

{cl.CountryCode, cl.Language} -> {cl.*}

さらに、WHERE 句の等価性のため、次のようになります:

{cl.CountryCode} -> {co.Code}

また、co.Codeco の主キーであるため、次のようになります:

{co.Code} -> {co.*}

「一意に決定」関係は推移的であるため、次のようになります:

{cl.CountryCode, cl.Language} -> {cl.*,co.*}

その結果、クエリーは有効になります。

前の例と同様に、NOT NULL カラムに対する UNIQUE キーを主キーのかわりに使用できます。

WHERE のかわりに INNER JOIN 条件を使用できます。 同じ機能依存性が適用されます:

SELECT co.Name, cl.Language,
cl.Percentage * co.Population/100.0 AS SpokenBy
FROM countrylanguage cl INNER JOIN country co
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

関数従属性特殊ケース

WHERE 条件または INNER JOIN 条件での等価テストは対称ですが、テーブルは異なる役割を果たすため、外部結合条件での等価テストは対称ではありません。

参照整合性が誤って破損し、対応する行がない countrylanguage の行が country に存在するとします。 前述の例と同じクエリーを考えてみますが、LEFT JOIN の場合は次のようになります:

SELECT co.Name, cl.Language,
cl.Percentage * co.Population/100.0 AS SpokenBy
FROM countrylanguage cl LEFT JOIN country co
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

cl.CountryCode の特定の値について、結合結果の co.Code の値は、一致する行 (cl.CountryCode によって決定) で検出されるか、一致がない場合は NULL で補完されます (cl.CountryCode によっても決定されます)。 いずれの場合も、この関係が適用されます:

{cl.CountryCode} -> {co.Code}

cl.CountryCode 自体は、主キーである {cl.CountryCode, cl.Language} に機能的に依存します。

結合結果で、co.CodeNULL で補完されている場合、co.Name も同様です。 co.CodeNULL で補完されていない場合、co.Code は主キーであるため、co.Name が決定されます。 したがって、すべての場合で次のようになります:

{co.Code} -> {co.Name}

次のものが生成されます:

{cl.CountryCode, cl.Language} -> {cl.*,co.*}

その結果、クエリーは有効になります。

ただし、次のクエリーのようにテーブルがスワップされるとします:

SELECT co.Name, cl.Language,
cl.Percentage * co.Population/100.0 AS SpokenBy
FROM country co LEFT JOIN countrylanguage cl
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

現在、この関係は適用されません:

{cl.CountryCode, cl.Language} -> {cl.*,co.*}

実際には、cl に対して作成された NULL で補完されたすべての行は単一のグループに配置され (両方の GROUP BY カラムが NULL と等しい)、このグループ内で co.Name の値が異なる可能性があります。 クエリーが無効であり、MySQL によって拒否されます。

したがって、外部結合の関数従属性は、決定要因カラムが LEFT JOIN の左側に属するか右側に属するかにリンクされます。 ネストされた外部結合がある場合、または結合条件が完全に等価比較で構成されていない場合、関数従属性の決定はより複雑になります。

関数従属性とビュー

国のビューでは、コード、名前 (大文字)、および国が持つ異なる公用語の数が生成されるとします:

CREATE VIEW country2 AS
SELECT co.Code, UPPER(co.Name) AS UpperName,
COUNT(cl.Language) AS OfficialLanguages
FROM country AS co JOIN countrylanguage AS cl
ON cl.CountryCode = co.Code
WHERE cl.isOfficial = 'T'
GROUP BY co.Code;

この定義は、次の理由で有効です:

{co.Code} -> {co.*}

ビュー結果では、最初に選択されたカラムは co.Code であり、これはグループカラムでもあるため、選択された他のすべての式が決定されます:

{country2.Code} -> {country2.*}

次に説明するように、MySQL はこれを理解し、この情報を使用します。

このクエリーでは、city テーブルとビューを結合することで、国、国の公用語の数および市区町村の数が表示されます:

SELECT co2.Code, co2.UpperName, co2.OfficialLanguages,
COUNT(*) AS Cities
FROM country2 AS co2 JOIN city ci
ON ci.CountryCode = co2.Code
GROUP BY co2.Code;

前述のとおり、このクエリーは次の理由で有効です:

{co2.Code} -> {co2.*}

MySQL では、ビューの結果で関数従属性を検出し、それを使用してビューを使用するクエリーを検証できます。 次のように、country2 が導出テーブル (または共通テーブル式) であった場合も同様です:

SELECT co2.Code, co2.UpperName, co2.OfficialLanguages,
COUNT(*) AS Cities
FROM
(
 SELECT co.Code, UPPER(co.Name) AS UpperName,
 COUNT(cl.Language) AS OfficialLanguages
 FROM country AS co JOIN countrylanguage AS cl
 ON cl.CountryCode=co.Code
 WHERE cl.isOfficial='T'
 GROUP BY co.Code
) AS co2
JOIN city ci ON ci.CountryCode = co2.Code
GROUP BY co2.Code;

関数従属性の組合せ

MySQL では、前述のすべてのタイプの関数従属性 (キーベース、等価ベース、ビューベース) を組み合せて、より複雑なクエリーを検証できます。