第三范式( 3NF ):如果關系模式 R ( U , F )中的所有非主屬性對任何候選關鍵字都不存在傳遞信賴,則稱關系 R 是屬於第三范式的。
例:如 S1 ( SNO , SNAME , DNO , DNAME , LOCATION ) 各屬性分別代表學號,姓名,所在系,系名稱,系地址。
關鍵字 SNO 決定各個屬性。由於是單個關鍵字,沒有部分依賴的問題,肯定是 2NF 。但這關系肯定有大量的冗余,有關學生所在的幾個屬性 DNO , DNAME , LOCATION 將重復存儲,插入,刪除和修改時也將產生類似以上例的情況。
原因:關系中存在傳遞依賴造成的。由於 SNAME 和 DNO 是依賴 SNO ,而 DNAME 和 LOCATION 是依賴 DNO 的,即通過一個學號可以知道該學生的姓名以及他所在系代碼,但無法由學號知道系地址,學號和系地址間是通過學號所對應的學生的所在系關聯的, 因此關鍵字 SNO 對 LOCATION 函數決定是通過傳遞依賴 DNO -> LOCATION 實現的。也就是說, SNO 不直接決定非主屬性 LOCATION 。
解決目地:每個關系模式中不能留有傳遞依賴。
解決方法:分為兩個關系 S ( SNO , SNAME , DNO ), D ( DNO , DNAME , LOCATION )
注意:關系 S 中不能沒有外關鍵字 DNO 。否則兩個關系之間失去聯系。
在數據庫的設計過程中常常按照第三范式來設計數據庫,當然在有些場合為優化數據庫的性能而增加了相關冗余字段以使表的結構不符合 3NF ,在多數場合中,沒有一張表能完整的發揮客戶所需要的結果集。這樣就需要通過聯接多張在邏輯上存在依賴關系的表,選擇你所需要的數據。
在使用 JOIN 前,必須明白是通過聯接,根據各個表之間的邏輯關系從相關表中檢索數據。通過 SQL Server 自帶幫助文件,可以清楚的知道:可在 FROM 或 WHERE 子句中指定聯接。
下例使用 WHERE 子句進行表之間的
SELECT A.SYMBOL,A.SNAME,B.TDATE,B.CLOSE
FROM SECURITYCODE A,DAYQUOTE B
WHERE A.SYMBOL =B.SYMBOL
AND B.TDATE >= A.LISTDATE
AND A.SYMBOL LIKE ‘600%’
在上例中聯接的表 A 與表 B 通過 A.SYMBOL =B.SYMBOL 這個條件聯接,篩選條件為 B.TDATE 不小於 A. LISTDATE 。
在 WHERE 子句中指定聯接,對於較簡單的聯接,使用這種方式可能較方便,但綜合來說,不推薦使用該語法聯接表。
拿上面的例子來詳細說,表 SECURITYCODE 中主要存放證券代碼的基本信息,表中的 SYMBOL 代表股票代碼, SNAME 代表股票名稱, LISTDATE 代表上市日期;表 DAYQUOTE 中主要存放股票的每日行情。 SYMBOL 代表股票代碼, TDATE 代表交易日期, CLOSE 代表收盤價。
我現在的取值邏輯是:取出股票代碼以 600 打頭的股票自上市日期以來的所有交易日的收盤價。將 SECURITYCODE 與 DAYQUOTE 通過 SYMBOL 聯接。
SELECT A.SYMBOL,A.SNAME,B.TDATE,B. CLOSE
FROM SECURITYCODE A
JOIN DAYQUOTE B
ON A.SYMBOL =B.SYMBOL
WHERE B.TDATE >= A.LISTDATE
AND A.SYMBOL LIKE ‘600%’
ORDER BY A.SYMBOL,B.TDATE
對於使用 FROM 子句方式聯接表,可以很清楚的看出表之間的聯接條件。就可讀性以及後續的可修改性與 WHERE 子句相比有較大的優勢。
下面就聯接的方式引用幫助文件中的具體介紹,聯接可以分為以下幾種:
內聯接(典型的聯接運算,使用像 = 或 <> 之類的比較運算符)。包括相等聯接和自然聯接。
內聯接使用比較運算符根據每個表共有的列的值匹配兩個表中的行。
在 SQL-92 標准中,內聯接可在 FROM 或 WHERE 子句中指定。這是 WHERE 子句中唯一一種 SQL-92 支持的聯接類型。 WHERE 子句中指定的內聯接稱為舊式內聯接。
內聯接一般常見寫法:
SELECT A.COLUMN1,[A.COLUMN2],B.COLUMN1,[B.COLUMN2]
FROM TABLE1 A
[INNER] JOIN TABLE2 B
ON A.COLUMN0 = B.COLUMN0
在查詢分析器中使用 INNER JOIN 時常常省略 INNER 。
外聯接可以是左向外聯接、右向外聯接或完整外部聯接。
在 FROM 子句中指定外聯接時,可以由下列幾組關鍵字中的一組指定:
LEFT JOIN 或 LEFT OUTER JOIN
左向外聯接的結果集包括 LEFT OUTER 子句中指定的左表的所有行,而不僅僅是聯接列所匹配的行。如果左表的某行在右表中沒有匹配行,則在相關聯的結果集行中右表的所有選擇列表列均為空值。
RIGHT JOIN 或 RIGHT OUTER JOIN
右向外聯接是左向外聯接的反向聯接。將返回右表的所有行。如果右表的某行在左表中沒有匹配行,則將為左表返回空值。
FULL JOIN 或 FULL OUTER JOIN
完整外部聯接返回左表和右表中的所有行。當某行在另一個表中沒有匹配行時,則另一個表的選擇列表列包含空值。如果表之間有匹配行,則整個結果集行包含基表的數據值。
僅當至少有一個同屬於兩表的行符合聯接條件時,內聯接才返回行。內聯接消除與另一個表中的任何行不匹配的行。而外聯接會返回 FROM 子句中提到的至少一個表或視圖的所有行,只要這些行符合任何 WHERE 或 HAVING 搜索條件。將檢索通過左向外聯接引用的左表的所有行,以及通過右向外聯接引用的右表的所有行。完整外部聯接中兩個表的所有行都將返回。
外聯接的中常見的是 LEFT JOIN ,將 LEFT JOIN 用熟已經可以解決大半問題了。
外聯接的一般寫法:
SELECT A.COLUMN1,[A.COLUMN2],B.COLUMN1,[B.COLUMN2]
FROM TABLE1 A
LEFT|RIGHT|FULL [OUTER] JOIN TABLE2 B
ON A.COLUMN0 = B.COLUMN0
在查詢分析器中使用 OUTER JOIN 時常常省略 OUTER 。 LEFT 和 RIGHT 只是方向問題,在特定場合下, FULL OUTER JOIN 相當於 LEFT OUTER JOIN 和 RIGHT OUTER JOIN 的消除重復行的合集。
交叉聯接返回左表中的所有行,左表中的每一行與右表中的所有行組合。交叉聯接也稱作笛卡爾積。
沒有 WHERE 子句的交叉聯接將產生聯接所涉及的表的笛卡爾積。第一個表的行數乘以第二個表的行數等於笛卡爾積結果集的大小。也就是說在沒有 WHERE 子句的情況下,若表 A 有 3 行記錄,表 B 有 6 行記錄 : :
SELECT A.*,B.* FROM 表A CROSS JOIN 表B
那以上語句會返回 18 行記錄。