以下討論提供數個範例,說明 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.Code
是 co
的主索引鍵,因此 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.Code
是 co
的主索引鍵
{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;