1. 程式人生 > >產品讀書《SQL必知必會》

產品讀書《SQL必知必會》

       大學期間學過資料庫相關的知識,無奈幾年下來能吃到肚子裡的都吃進去了,留在腦子裡的恐怕沒多少了,其實之前也沒有認認真真的學習過資料庫,全靠實踐中一點點查,還好也不算晚,看一本非常基礎但是比較全面的基礎書來補一補N多年前的知識,就當是複習筆記吧! 很遺憾的一點是在這本書的讀書筆記裡面我不會太過詳細的記錄具體的語法,更多的是回顧,如若不詳細,還請各位移步原著去通讀一遍!但也希望與我有益的同時幫助到您!

目錄

二 檢索資料

四 過濾資料

九 彙總資料

十 分組資料

思維導圖

一 瞭解資料庫SQL

  • 資料庫(database) vs 資料庫管理系統(DBMS)
  • 表(table)、模式(schema)
  • 列(column)、資料型別(datatype)
  • 行(row)
  • 主鍵(primary key):應該總是定義主鍵

二 檢索資料

  • 檢索單個列
SELECT PROD_NAME 
FROM Product;
  • 檢索多個列
SELECT prod_id, prod_name, prod_price
FROM Products;
  • 檢索所有列
SELECT *
FROM Products;
  • 檢索不同值:不能部分使用DISTINCT
SELECT DISTINCT vend_id
FROM Products;
  • 限制結果
SQL SERVER & Access :TOP  DB2: Oracle:ROWNNUM MySQL、MariaDB、PostgreSQL或者SQLite: LIMIT
SELECT TOP 5 prod_name
FROM Products;
SELECT prod_name
FROM Products
FETCH FIRST 5 ROWS ONLY;
SELECT prod_name
FROM Products
WHERE ROWNUM <=5;
SELECT prod_name
FROM Products
LIMIT 5 OFFSET 5;       -- 從第5行起ide5行資料

補充

#1. 這是一條註釋

/*2. 這是多

行註釋*/

--3. 這是另外一種註釋:從第5行起ide5行資料

三 排序檢索資料

  • 排序資料
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price;
  • 按多個列排序檢索資料
#僅在多個行具有相同的prod_price值時才對產品按prod_name進行排序。如果prod_price列中所有的值都是唯一的,則不會按prod_name排序

SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price, prod_name;
  • 按列位置進行排序:不建議
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY 2, 3;
  • 指定排序方向:預設升序,DESC降序,且只對其前面的有效
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price DESC,prod_name;   --只對prod_price列指定DESC,對prod_name列不指定

四 過濾資料

  • where語句:警告:在同時使用ORDER BY和WHERE子句時,應該讓ORDER BY位於WHERE之後,否則將會產生錯誤
SELECT prod_name, prod_price
FROM Products
WHERE prod_price = 3.49;
  • where字句操作符:

五 高階資料過濾

  • AND 
  • OR 

AND 和OR組合使用時:AND優先順序>OR,因此需要將OR語句用()括起來

SELECT prod_name,prod_price

FROM Products

WHERE (vend_id = 'DLL01' OR vend_id = 'BRS01')

AND prod_price >=10;

  • IN
  • NOT 

六 萬用字元進行過濾

LIKE

  • 百分號(%)萬用字元
  • 下劃線(_)萬用字元
  • 方括號([])萬用字元:方括號([])萬用字元用來指定一個字符集,它必須匹配指定位置(萬用字元的位置)的一個字元。

注意:

  • 不要過度使用萬用字元。如果其他操作符能達到相同的目的,應該使用其他操作符。
  • 在確實需要使用萬用字元時,也儘量不要把它們用在搜尋模式的開始處。把萬用字元置於開始處,搜尋起來是最慢的。
  • 仔細注意萬用字元的位置。如果放錯地方,可能不會返回想要的資料。

七 建立計算欄位

(1)拼接欄位(將值聯結到一起構成單個值)

  • concat函式(mysql用):select concat(vend_id,’ (‘,vend_country,’)’) #select語句聯結以上4個元素。
  • ‘+’號(Access,SQL Server,Sybase使用):select vend_id + ‘ (‘ + vend_country + ‘)’。
  • ‘||’號(DB2,Oracle使用):select vend_id || ‘ (‘ || vend_country || ‘)’。
  • TRIM函式:RTRIM()去掉值右邊所有空格,LTRIM()去掉值左邊所有空格,TRIM()去掉值兩邊所有空格。
  • AS關鍵字:給聯結欄位取別名。
  • 完整聯結欄位語句: select RTRIM(vend_id) + ‘ (‘ + TRIRM(vend_country) + ‘)’ AS vendor_title FROM Vendors ORDER BY vend_name。

(2)執行算數計算:+、-、*、/

八 使用資料處理函式

SQL函式不可移植;

(1)文字處理函式:

注:SOUNDEX將任何文字串轉換為描述其語音表示的字母數字模式。SOUNDEX考慮了類似的發音字元和音節,使得能對字串進行發音比較而不是字母比較。

(2)日期和時間處理函式

DATAPART()、to_date()等,不同環境語法不同;

(3)數值處理

九 彙總資料

(1)聚集函式

(2)聚集不同值:DISTINCT

警告:DISTINCT不能用於COUNT(*)
如果指定列名,則DISTINCT只能用於COUNT()。DISTINCT不能用於COUNT(*)。類似地,DISTINCT必須使用列名,不能用於計算或表示式。

提示:將DISTINCT用於MIN()和MAX()
雖然DISTINCT從技術上可用於MIN()和MAX(),但這樣做實際上沒有價值。一個列中的最小值和最大值不管是否只考慮不同值,結果都是相同的。

(3)組合聚集函式

十 分組資料

(1)GROUP BY

  • GROUP BY子句可以包含任意數目的列,因而可以對分組進行巢狀,更細緻地進行資料分組。
  • 如果在GROUP BY子句中嵌套了分組,資料將在最後指定的分組上進行彙總。換句話說,在建立分組時,指定的所有列都一起計算(所以不能從個別的列取回資料)。
  • GROUP BY子句中列出的每一列都必須是檢索列或有效的表示式(但不能是聚集函式)。如果在SELECT中使用表示式,則必須在GROUP BY子句中指定相同的表示式。不能使用別名。
  • 大多數SQL實現不允許GROUP BY列帶有長度可變的資料型別(如文字或備註型欄位)。
  • 除聚集計算語句外,SELECT語句中的每一列都必須在GROUP BY子句中給出。
  • 如果分組列中包含具有NULL值的行,則NULL將作為一個分組返回。如果列中有多行NULL值,它們將分為一組。
  • GROUP BY子句必須出現在WHERE子句之後,ORDER BY子句之前。

(2)過濾分組Having: where過濾行,Having過濾分組

說明:HAVING和WHERE的差別
這裡有另一種理解方法,WHERE在資料分組前進行過濾,HAVING在資料分組後進行過濾。這是一個重要的區別,WHERE排除的行不包括在分組中。這可能會改變計算值,從而影響HAVING子句中基於這些值過濾掉的分組。

(3)分組和排序

(4)SELECT子句順序

十一 使用子查詢

(1)利用子查詢進行過濾

SELECT cust_id
FROM Order
WHERE order_num IN (SELECT order_num
                    FROM OrderItems
                    WHERE prod_id = 'RGAN01');

警告::只能是單列

作為子查詢的SELECT語句只能查詢單個列。企圖檢索多個列將返回錯誤。 

子查詢常用於WHERE子句的IN操作符中,以及用來填充計算列。

(2)作為計算欄位使用子查詢

SELECT cust_name,
       cust_state,
      (SELECT COUNT(*)
       FROM Orders WHERE Orders.cust_id = Customers.cust_id) AS orders
FROM Customers ORDER BY cust_name;

注:子查詢中的WHERE子句與前面使用的WHERE子句稍有不同,因為它使用了完全限定列名,而不只是列名(cust_id)
 

十二、聯結表&高階聯結表

1. 使用別名:AS

2. 建立聯結

a. 等值聯結,又叫內聯結(inner join)

原始:

SELECT vend_name, prod_name, prod_price
FROM Vendors, Products 
WHERE Vendors.vend_id = Products.vend_id;

內聯結: 

SELECT vend_name, prod_name, prod_price 
FROM Vendors INNER JOIN Products
ON Vendors.vend_id = Products.vend_id;

警告::完全限定列名--在引用的列可能出現歧義時,必須使用完全限定列名(用一個句點分隔表名和列名,eg:Vendors.vend_id)。

注意:
由沒有聯結條件的表關係返回的結果為笛卡兒積(叉聯結(cross join))。檢索出的行的數目將是第一個表中的行數乘以第二個表中的行數,要保證所有聯結都有WHERE子句,否則DBMS將返回比想要的資料多得多的資料。

b. 自聯結(self-join)

提示:用自聯結而不是子查詢
自聯結通常作為外部語句,用來替代從相同表中檢索資料的使用子查詢語句。雖然最終的結果是相同的,但許多DBMS處理聯結遠比處理子查詢快得多。

子查詢:
SELECT cust_id, cust_name, cust_contact
FROM Customers WHERE cust_name = (SELECT cust_name
                                  FROM Customers 
                                  WHERE cust_contact = 'Jim Jones');
自聯結:
SELECT c1.cust_id, c1.cust_name, c1.cust_contact
FROM Customers AS c1, Customers AS c2
WHERE c1.cust_name = c2.cust_name
AND c2.cust_contact = 'Jim Jones';

c.自然聯結(natural join)

自然聯結排除多次出現,使每一列只返回一次,迄今為止建立的每個內聯結都是自然聯結,很可能永遠都不會用到不是自然聯結的內聯結.

SELECT C.*, O.order_num, O.order_date, OI.prod_id, OI.quantity, OI.item_price
FROM Customers AS C, Orders AS O, OrderItems AS OI
WHERE C.cust_id = O.cust_id
AND OI.order_num = O.order_num
AND prod_id = 'RGAN01';

d. 外聯結(outer join):

聯結包含了那些在相關表中沒有關聯行的行。這種聯結稱為外聯結。

SELECT Customers.cust_id, Orders.order_num
FROM Customers LEFT OUTER JOIN Orders 
ON Customers.cust_id = Orders.cust_id
  • 左外聯結:使用LEFT OUTER JOIN從FROM子句左邊的表中選擇所有行
  • 右外聯結: 使用RIGHT OUTER JOIN從FROM子句右邊的表中選擇所有行
  • 全外聯結(full outer join):檢索兩個表中的所有行並關聯那些可以關聯的行,全外聯結包含兩個表的不關聯的行

e. 使用帶聚集函式的聯結

十四、組合查詢(並UNION、符合查詢)

主要有兩種情況需要使用組合查詢:

  • 在一個查詢中從不同的表返回結構資料;
  • 對一個表執行多個查詢,按一個查詢返回資料
SELECT cust_name, cust_contact, cust_email
FROM Customers WHERE cust_state IN ('IL','IN','MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers WHERE cust_name = 'Fun4All';

十五、資料插入

1. 插入完整/部分的行

INSERT INTO Customers(cust_id,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country,cust_contact,)
VALUES('1000000006','Toy Land','123 Any Street','New York','NY','11111','USA',NULL,);

警告:小心使用VALUES
不管使用哪種INSERT語法,VA LUES的數目都必須正確。如果不提供列名,則必須給每個表列提供一個值;如果提供列名,則必須給列出的每個列一個值。否則,就會產生一條錯誤訊息,相應的行不能成功插入。

2.插入檢索出的資料

INSERT INTO Customers(cust_id,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country,cust_contact)

SELECT cust_id,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country,cust_contact

FROM CustNew

說明:

INSERT SELECT與SELECT INTO
它們之間的一個重要差別是前者匯出資料,而後者匯入資料。

3. 從一個表複製到另一個表

SELECT *
INTO CustCopy
FROM Customers;

MariaDB、MySQL、Oracle、PostgreSQL和SQLite使用:

CREATE TABLE CustCopy AS
SELECT * FROM Customers;

十六、更新和刪除資料

1. 更新資料

UPDATE Customers
SET cust_contact = 'Sam Roberts',
    cust_email = '[email protected]'
WHERE cust_id = '1000000006';
UPDATE Customers
SET cust_email = NULL
WHERE cust_id = '1000000005';

注:其中NULL用來去除cust_email列中的值。這與儲存空字串很不同(空字串用''表示,是一個值),而NULL表示沒有值。 

2.刪除資料

DELETE FROM Customers
WHERE cust_id = '1000000006';
  • DELETE不需要列名或萬用字元。DELETE刪除整行而不是刪除列。要刪除指定的列使用UPDATE語句。
  • DELETE語句從表中刪除行,甚至是刪除表中所有行。但是,DELETE不刪除表本身。
  • 如果想從表中刪除所有行,不使用DELETE。可使用TRUNCATE TABLE語句,它完成相同的工作,而速度更快。

十七、建立和操縱表

1、建立表

CREATE TABLE Products
(
prod_id CHAR(10) NOT NULL,
vend_id CHAR(10) NOT NULL,
prod_name CHAR(254) NOT NULL,
prod_price DECIMAL(8,2) NOT NULL DEFAULT 10,
prod_desc VARCHAR(1000) NULL
);

提示:替換現有的表
在建立新的表時,指定的表名必須不存在,否則會出錯。防止意外覆蓋已有的表,SQL要求首先手工刪除該表(請參閱後面的內容),然後再重建它,而不是簡單地用建立表語句覆蓋它。

1.1、使用NULL值

  • NULL值就是沒有值或缺值。允許NULL值的列也允許在插入行時不給出該列的值。不允許NULL值的列不接受沒有列值的行,換句話說,在插入或更新行時,該列必須有值。
  • NULL為預設設定,如果不指定NOT NULL,就認為指定的是NULL。
  • 在不指定NOT NULL時,多數DBMS認為指定的是NULL,但不是所有的DBMS都這樣。DB2要求指定關鍵字NULL,如果不指定將出錯。
  • 主鍵是其值唯一標識表中每一行的列。只有不允許NULL值的列可作為主鍵,允許NULL值的列不能作為唯一標識。
  • 不要把NULL值與空字串相混淆。NULL值是沒有值,不是空字串。如果指定''(兩個單引號,其間沒有字元),這在NOT NULL列中是允許的。空字串是一個有效的值,它不是無值。NULL值用關鍵字NULL而不是空字串指定。

1.2.使用預設值DEFAULT

2.更新表

ALTER TABLE Vendors
ADD vend_phone CHAR(20);
DROP COLUMN vend_phone;

3.刪除表

DROP TABLE CustCopy;

 注:刪除表(刪除整個表而不是其內容)

4.重命名錶

RENAME、sp_rename、ALTER TABLE(都要求指定舊錶名和新表名)

十八、使用檢視

檢視是虛擬的表,檢視本身不包含資料,因此它們返回的資料是從其他表中檢索出來的,在更改這些表中的資料時,檢視將返回改變過後的資料。

(1)檢視的規則和限制

  • 檢視可以巢狀;
  • 禁止在檢視查詢時使用ORDER BY語句。

(2)建立檢視(creat view)

  • 利用檢視簡化複雜的聯結;
  • 用檢視重新格式化檢索出的資料;
  • 用檢視過濾不想要的資料(where子句);
  • 使用檢視與計算欄位。

說明:檢視重新命名
刪除檢視,可以使用DROP語句,其語法為DROP VIEW viewname;。
覆蓋(或更新)檢視,必須先刪除它,然後再重新建立。

十九、使用儲存過程

為以後的使用而儲存一條或多條SQL語句的集合。

二十、管理事務處理

(1)什麼是事務處理

事務管理用來管理必須成批執行的SQL操作,以保證資料庫不包含不完整的操作結果。利用事務處理,可以保證一組資料不會中途停止,它們或者作為整體執行,或者完全不執行(除非明確指示)。

如果沒有錯誤發生,則整組語句寫到資料庫表,如果發生錯誤,則進行回退(撤銷)以恢復資料庫到某個已知且安全的狀態。

(2)幾個術語

  • 事務(transction):一組SQL語句;
  • 回退(rollback):指撤銷指定SQL語句的過程;
  • 提交(commit):指將未儲存的SQL語句結果寫入資料庫表;
  • 保留點(savepoint):指事務處理中設定的臨時佔位符,你可以對它釋出回退(與回退整個事務處理不同)。

(3)可以回退哪些語句

可管理INSERT,UPDATE,DELETE語句,不能回退SELECT語句也不能回退CREATE,DROP操作。事務處理中可以使用這些語句,但回退時它們不被撤銷。

(4)控制事務處理

在這個例子中,BEGIN TRA NSA CTION和COMMIT TRA NSA CTION語句之間的SQL必須完全執行或者完全不執行。

BEGIN TRANSACTION
...
COMMIT TRANSACTION

其他:

START、SET TRANSCATION...COMMIT、BEGIN。。。其他DBMS採用上述語法的變體。多數實現沒有明確標識事務處理在何處結束。事務一直存在,直到被中斷。通常,COMMITT用於儲存更改,ROLLBA CK用於撤銷。

1.ROLLBACK

DELETE FROM Orders;
ROLLBACK;

分析:執行DELETE操作,然後用ROLLBA CK語句撤銷。

2. COMMIT

BEGIN TRANSACTION
DELETE OrderItems WHERE order_num = 12345
DELETE Orders WHERE order_num = 12345
COMMIT TRANSACTION

分析:從系統中完全刪除訂單12345。因為涉及更新兩個資料庫表Orders和OrderItems,所以使用事務處理塊來保證訂單
不被部分刪除。最後的COMMIT語句僅在不出錯時寫出更改。如果第一條DELETE起作用,但第二條失敗,則DELETE不會提交。

3. 保留點(佔位符)

提示:可以在SQL程式碼中設定任意多的保留點,因為保留點越多,你就越能靈活地進行回退。

  • mysql: savepoint delete1;------>rollback to delete1;
  • sql server:save trasaction delete1; #delete1為此佔位符的名字。 ------>  rollback transaction delete1;#回退到保留點delete1;

二十一、使用遊標(cursor)

遊標不是一條select語句,而是被該語句檢索出來的結果集,在儲存了遊標之後,應用程式可以根據需要滾動或瀏覽其中的資料。遊標主要用於互動式應用,其中使用者需要滾動螢幕上的資料,並對資料進行瀏覽或更改。

  • 宣告:declare
DECLARE CustCursor CURSOR
FOR
SELECT * FROM Customers
WHERE cust_email IS NULL
  • 開啟:open cursor,在處理OPEN CURSOR語句時,執行查詢,儲存檢索出的資料以供瀏覽和滾動。
  • 檢索:fetch… into…
  • 關閉:close   一旦遊標關閉,如果不再次開啟,將不能使用。第二次使用它時不需要再宣告,只需用OPEN開啟它即可

二十二 、高階SQL特性

約束:管理如何插入或處理資料庫資料的規則

主鍵:一種特殊約束PRIMARY KEY

CREATE TABLE Vendors
(
vend_id CHAR(10) NOT NULL PRIMARY KEY,
vend_name CHAR(50) NOT NULL,
vend_country CHAR(50) NULL
);
ALTER TABLE Vendors
ADD CONSTRAINT PRIMARY KEY (vend_id);

外來鍵:可幫助防止意外刪除,

CREATE TABLE Orders
(
order_num INTEGER NOT NULL PRIMARY KEY,
order_date DATETIME NOT NULL,
cust_id CHAR(10) NOT NULL REFERENCES Customers(cust_id)
);
ALTER TABLE Orders
ADD CONSTRAINT
FOREIGN KEY (cust_id) REFERENCES Customers (cust_id)

 唯一約束:UNIQUE 唯一約束用來保證一列(或一組列)中的資料是唯一的。它們類似於主鍵,但存在以下重要區別。

  • 表可包含多個唯一約束,但每個表只允許一個主鍵。
  • 唯一約束列可包含NULL值。
  • 唯一約束列可修改或更新。
  • 唯一約束列的值可重複使用。
  • 與主鍵不一樣,唯一約束不能用來定義外來鍵。

檢查約束:檢查約束用來保證一列(或一組列)中的資料滿足一組指定的條件。檢查約束的常見用途有以下幾點。

  • 檢查最小或最大值。例如,防止0個物品的訂單(即使0是合法的數)。
  • 指定範圍。例如,保證發貨日期大於等於今天的日期,但不超過今天起一年後的日期。
  • 只允許特定的值。例如,在性別欄位中只允許M或F。
CREATE TABLE OrderItems
(
order_num INTEGER NOT NULL,
order_item INTEGER NOT NULL,
prod_id CHAR(10) NOT NULL,
quantity INTEGER NOT NULL CHECK (quantity > 0),
item_price MONEY NOT NULL
);
分析▼
ADD CONSTRAINT CHECK (gender LIKE '[MF]')

 索引:,就是恰當的排序,索引必須唯一命名

CREATE INDEX prod_name_ind
ON PRODUCTS (prod_name);
  • 索引改善檢索操作的效能,但降低了資料插入、修改和刪除的效能。在執行這些操作時,DBMS必須動態地更新索引。
  • 索引資料可能要佔用大量的儲存空間。
  • 並非所有資料都適合做索引。取值不多的資料(如州)不如具有更多可能值的資料(如姓或名),能通過索引得到那麼多的好處。
  • 索引用於資料過濾和資料排序。如果你經常以某種特定的順序排序資料,則該資料可能適合做索引。
  • 可以在索引中定義多個列(例如,州加上城市)。這樣的索引僅在以州加城市的順序排序時有用。如果想按城市排序,則這種索引沒有用處。

觸發器:觸發器是特殊的儲存過程,它在特定的資料庫活動發生時自動執行。觸發器可以與特定表上的INSERT、UPDA TE和DELETE操作(或組合)相關聯。

  • 保證資料一致。例如,在INSERT或UPDATE操作中將所有州名轉換為大寫。
  • 基於某個表的變動在其他表上執行活動。例如,每當更新或刪除一行時將審計跟蹤記錄寫入某個日誌表。
  • 進行額外的驗證並根據需要回退資料。例如,保證某個顧客的可用資金不超限定,如果已經超出,則阻塞插入。
  • 計算計算列的值或更新時間戳。
CREATE TRIGGER customer_state
ON Customers
FOR INSERT, UPDATE
AS
UPDATE Customers
SET cust_state = Upper(cust_state)
WHERE Customers.cust_id = inserted.cust_id;

資料庫安全:安全性使用SQL的GRA NT和REVOKE語句來管理,不過,大多數DBMS提供了互動式的管理實用程式,這些實用程式在內部使用GRA NT和REVOKE語句。 

思維導圖

SQL必知必會腦圖