次の説明では、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.Code
は co
の主キーであるため、次の表記法を使用して表されるように、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.CountryCode
、cl.Language
) は cl
の 2 カラム複合主キーであるため、カラムのペアによって cl
のすべてのカラムが一意に決定されます:
{cl.CountryCode, cl.Language} -> {cl.*}
さらに、WHERE
句の等価性のため、次のようになります:
{cl.CountryCode} -> {co.Code}
また、co.Code
は co
の主キーであるため、次のようになります:
{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.Code
が NULL
で補完されている場合、co.Name
も同様です。 co.Code
が NULL
で補完されていない場合、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;