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


MySQL 9.0 參考手冊  /  ...  /  函數相依性的偵測

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.CountryCodecl.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 決定),就是如果沒有相符項目,則以 NULL 補足(也由 cl.CountryCode 決定)。在每個案例中,此關係都適用

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

cl.CountryCode 本身在函數上相依於 {cl.CountryCodecl.Language},後者是主索引鍵。

如果聯結結果中的 co.CodeNULL 補足,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 能夠結合所有前面類型的函數相依性(基於鍵、基於相等、基於視圖),以驗證更複雜的查詢。