以下討論提供 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
決定),就是如果沒有相符項目,則以 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;