天天看點

SQL 程式設計思想:一切皆關系

SQL 程式設計思想:一切皆關系

在計算機領域有許多偉大的設計理念和思想,例如:

在 Unix 中,一切皆檔案。

在面向對象的程式設計語言中,一切皆對象。

關系資料庫同樣也有自己的設計思想:在 SQL 中,一切皆關系。

關系模型(Relational model)由 E.F.Codd 博士于 1970 年提出,以集合論中的關系概念為基礎;無論是現實世界中的實體對象還是它們之間的聯系都使用關系表示。我們在資料庫系統中看到的關系就是二維表(Table),由行(Row)和列(Column)組成。是以,也可以說關系表是由資料行構成的集合。

SQL 程式設計思想:一切皆關系

關系模型由資料結構、關系操作、完整性限制三部分組成。

關系模型中的資料結構就是關系表,包括基礎表、派生表(查詢結果)和虛拟表(視圖)。

常用的關系操作包括增加、删除、修改和查詢(CRUD),使用的就是 SQL 語言。其中查詢操作最為複雜,包括選擇(Selection)、投影(Projection)、并集(Union)、交集(Intersection)、差集(Exception)以及笛卡兒積(Cartesian product)等。

完整性限制用于維護資料的完整性或者滿足業務限制的需求,包括實體完整性(主鍵限制)、參照完整性(外鍵限制)以及使用者定義的完整性(非空限制、唯一限制、檢查限制和預設值)。

我們今天的主題是關系操作語言,也就是 SQL。本文使用的示例資料來源于這篇文章。

SQL(結構化查詢語言)是操作關系資料庫的标準語言。SQL 非常接近英語,使用起來非常簡單。它在設計之初就考慮了非技術人員的使用需求,我們通常隻需說明想要的結果(What),而将資料處理的過程(How)交給資料庫管理系統。是以說,SQL 才是真正給人用的程式設計語言!😎

接下來我們具體分析一下關系的各種操作語句;目的是為了讓大家能夠了解 SQL 是一種面向集合的程式設計語言,它的操作對象是集合,操作的結果也是集合。

📝在關系資料庫中,關系、表、集合三者通常表示相同的概念。

下面是一個簡單的查詢語句:

它的作用就是從 employees 表中查詢員工資訊。顯然,我們都知道 FROM 之後是一個表(關系、集合)。不僅如此,整個查詢語句的結果也是一個表。是以,我們可以将上面的查詢作為表使用:

括号内的查詢語句被稱為派生表,我們給它指定了一個别名叫做 t。同樣,整個查詢結果也是一個表;這就意味着我們可以繼續嵌套,雖然這麼做很無聊。

我們再看一個 PostgreSQL 中的示例:

upper() 是一個大寫轉換的函數。它出現再 FROM 子句中,意味着它的結果也是一個表,隻不過是 1 行 1 列的特殊表。

SELECT 子句用于指定需要查詢的字段,可以包含表達式、函數值等。SELECT 在關系操作中被稱為投影(Projection),看下面的示意圖應該就比較好了解了。

SQL 程式設計思想:一切皆關系

除了 SELECT 之外,還有一些常用的 SQL 子句。

WHERE 用于指定資料過濾的條件,在關系運算中被稱為選擇(Selection),示意圖如下:

SQL 程式設計思想:一切皆關系

ORDER BY 用于對查詢的結果進行排序,示意圖如下:

SQL 程式設計思想:一切皆關系

總之,SQL 可以完成各種資料操作,例如過濾、分組、排序、限定數量等;所有這些操作的對象都是關系表,結果也是關系表。

SQL 程式設計思想:一切皆關系

在這些關系操作中,有一個比較特殊,就是分組。

分組( GROUP BY)操作和其他的關系操作不同,因為它改變了關系的結構。來看下面的示例:

該語句的目的是按照部門統計員工的數量,但是存在一個文法錯誤,就是 first_name 不能出現在查詢清單中。原因在于按照部門進行分組的話,每個部門包含多個員工;無法确定需要顯示哪個員工的姓名,這是一個邏輯上的錯誤。

是以說,GROUP BY 改變了集合元素(資料行)的結構,建立了一個全新的關系。分組操作的示意圖如下:

SQL 程式設計思想:一切皆關系

盡管如此,GROUP BY 的結果仍然是一個集合。

SQL 面向集合特性最明顯的展現就是 UNION(并集運算)、INTERSECT(交集運算)和 EXCEPT/MINUS(差集運算)。

這些集合運算符的作用都是将兩個集合并成一個集合,是以需要滿足以下條件:

兩邊的集合中字段的數量和順序必須相同;

兩邊的集合中對應字段的類型必須比對或相容。

具體來說,UNION 和 UNION ALL 用于計算兩個集合的并集,傳回出現在第一個查詢結果或者第二個查詢結果中的資料。它們的差別在于 UNION 排除了結果中的重複資料,UNION ALL 保留了重複資料。下面是 UNION 操作的示意圖:

SQL 程式設計思想:一切皆關系

INTERSECT 操作符用于傳回兩個集合中的共同部分,即同時出現在第一個查詢結果和第二個查詢結果中的資料,并且排除了結果中的重複資料。INTERSECT 運算的示意圖如下:

SQL 程式設計思想:一切皆關系

EXCEPT 或者 MINUS 操作符用于傳回兩個集合的差集,即出現在第一個查詢結果中,但不在第二個查詢結果中的記錄,并且排除了結果中的重複資料。EXCEPT 運算符的示意圖如下:

SQL 程式設計思想:一切皆關系

除此之外,DISTINCT 運算符用于消除重複資料,也就是排除集合中的重複元素。

📝SQL 中的關系概念來自數學中的集合理論,是以 UNION、INTERSECT 和 EXCEPT 分别來自集合論中的并集($\cup$)、交集($\cap$)和差集($\setminus$)運算。需要注意的是,集合理論中的集合不允許存在重複的資料,但是 SQL 允許。是以,SQL 中的集合也被稱為多重集合(multiset);多重集合與集合理論中的集合都是無序的,但是 SQL 可以通過 ORDER BY 子句對查詢結果進行排序。

在 SQL 中,不僅實體對象存儲在關系表中,對象之間的聯系也存儲在關系表中。是以,當我們想要擷取這些相關的資料時,需要使用到另一個操作:連接配接查詢(JOIN)。

常見的 SQL連接配接查類型包括内連接配接、外連接配接、交叉連接配接等。其中,外連接配接又可以分為左外連接配接、右外連接配接以及全外連接配接。

内連接配接(Inner Join)傳回兩個表中滿足連接配接條件的資料,内連接配接的原理如下圖所示:

SQL 程式設計思想:一切皆關系

左外連接配接(Left Outer Join)傳回左表中所有的資料;對于右表,傳回滿足連接配接條件的資料;如果沒有就傳回空值。左外連接配接的原理如下圖所示:

SQL 程式設計思想:一切皆關系

右外連接配接(Right Outer Join)傳回右表中所有的資料;對于左表,傳回滿足連接配接條件的資料,如果沒有就傳回空值。右外連接配接與左外連接配接可以互換,以下兩者等價:

全外連接配接(Full Outer Join)等價于左外連接配接加上右外連接配接,同時傳回左表和右表中所有的資料;對于兩個表中不滿足連接配接條件的資料傳回空值。全外連接配接的原理如下圖所示:

SQL 程式設計思想:一切皆關系

交叉連接配接也稱為笛卡爾積(Cartesian Product)。兩個表的交叉連接配接相當于一個表的所有行和另一個表的所有行兩兩組合,結果的數量為兩個表的行數相乘。交叉連接配接的原理如下圖所示:

SQL 程式設計思想:一切皆關系
📝其他類型的連接配接還有半連接配接(SEMI JOIN)、反連接配接(ANTI JOIN)。

集合操作将兩個集合合并成一個更大或更小的集合;連接配接查詢将兩個集合轉換成一個更大或更小的集合,同時獲得了一個更大的元素(更多的列)。很多時候集合操作都可以通過連接配接查詢來實作,例如:

等價于:

我們已經介紹了許多查詢的示例,接下來看看其他的資料操作。

DML 表示資料操作語言,也就是插入、更新和删除。以下是一個插入語句示例:

我們通過一個 INSERT 語句插入了 3 條記錄,或者說是插入了一個包含 3 條記錄的關系表。因為,UNION ALL 傳回的是一個關系表。VALUES 同樣是指定了一個關系表,在 SQL Server 和 PostgreSQL 中支援以下語句:

前面我們已經說過,FROM 之後是一個關系表,是以這裡的 VALUES 也是一樣。由于我們經常插入單條記錄,并沒有意識到實際上是以表為機關進行操作。

同樣,UPDATE 和 DELETE 語句也都是以關系表為機關的操作;隻不過我們習慣了說更新一行資料或者删除幾條記錄。

如果覺得文章對你有用,請不要白嫖!歡迎關注❤️、點贊👍、轉發📣!