文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  函數依賴性偵測

14.19.4 函數依賴性偵測

以下討論提供數個範例,說明 MySQL 如何偵測函數依賴性。範例使用以下表示法

{X} -> {Y}

請理解為 X 唯一決定 Y,這也表示 Y 在功能上依賴於 X

範例使用 world 資料庫,該資料庫可從 https://mysqldev.dev.org.tw/doc/index-other.html 下載。您可以在同一個頁面找到如何安裝資料庫的詳細資訊。

從索引鍵衍生的函數依賴性

以下查詢選取每個國家/地區的口語語言計數

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 值的 UNIQUE 索引而言,情況並非如此,因為它允許多個 NULL 值,在這種情況下,唯一性會遺失。)

從多欄索引鍵和等式衍生的函數依賴性

此查詢選取每個國家/地區的所有口語語言清單以及使用這些語言的人數

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 的雙欄複合主索引鍵,因此該欄位對會唯一決定 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 索引來取代主索引鍵。

可以使用 INNER JOIN 條件來取代 WHERE。會套用相同的函數依賴性

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 決定),如果沒有相符項目 (也由 cl.CountryCode 決定),則會以 NULL 來補齊。在每種情況下,此關係都適用

{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;

函數相依性的組合

MySQL 能夠結合所有上述類型的函數相依性(基於鍵、基於相等性、基於視圖)來驗證更複雜的查詢。