先來幾張圖
前言
@author lgj
在讀電子版<<SQL必知必會>> 第4版時,做了下筆記。供以後自己或者其他學習者參考。
電子版<<SQL必知必會>>和書中使用的數據庫和表的源代碼,
請參看地址:https://github.com/thinkingfioa/Notes/tree/master/sql/SQL%E5%BF%85%E7%9F%A5%E5%BF%85%E4%BC%9A4
評價 本書適合入門,對數據庫查詢部分講解的比較好,之後的增刪改以及數據庫的其他特性講解的並不出衆,需要配合其他資料進一步學習。
第2課 檢索數據
2.3 檢索多個列
select column1, column2, column3 from tableName;
2.4 檢索所有的列
select * from products;
注:
1. 缺點:使用通配符(*),除非確實需要查詢表的每一列,否則可能會降低檢索和應用的性能.
2. 優點:能檢索出表的不明確的列。
2.5 檢索不同的值
select distinct vend_id from products;
注:
1. distinct關鍵字作用於作用於其後的所有的列,不僅僅是其後的一列。
2. 如:select distinct vend_id,prod_price from products;那麼這兩列vend_id, prod_price都同,纔會合併。
2.6 限制結果
- select prod_name from products limit 2; 返回結果只有2行。
- select prod_name from products limit 2 offset 5; 返6,7這2行數據。
- select prod_name from products limit 2 offset 5; 可以簡寫成 select prod_name from products limit 5,2;
注:
1. 第一個被檢索的行是第0行,而不是第1行。因此,LIMIT 1 OFFSET 1會檢索第2行,而不是第1行.
2. MySQL和MariaDB支持簡化版的LIMIT 4 OFFSET 3語句,即LIMIT 3,4。
2.7 使用註釋
- 單行註釋: #
- 多行註釋: /. ... /
第3課 排序檢索數據
使用Select子句的Order by子句,根據需要檢索排序出的數據
3.1 排序數據
使用Order by語句排序Select檢索出來的語句, Order by子句取一個或多個列的名字。
select prod_name, prod_price from products order by prod_price;
注:Order by子句, 必須是select的最後一條語句。
3.2 按多個列排序
select prod_name, prod_price, prod_id from products order by prod_price, prod_name;
3.3 按列位置排序
select prod_name, prod_price, prod_id from products order by 2, 3;
注:
1. order by 後面可以接數字,比如:2代表的是prod_price, 3代表的是prod_id。不推薦使用這種方式。
3.4 指定排序方向
ASC 升序(默認),DESC 降序。
- select prod_name, prod_price, prod_id from products order by prod_price DESC, prod_name;
- 如果DESC降序,必須對所有需要降序的列都要加上。
第4課 過濾數據
4.2.3 範圍值檢查
- select prod_name, prod_price, prod_id from products where prod_price between 4 and 10;
4.2.4 空值檢查
- select * from customers where cust_email is NULL; 空判斷過濾數據
- select * from customers where cust_email is not NULL; 非空判斷過濾數據
is null: 當列的值是 null,此運算符返回 true。
is not null: 當列的值不爲 null, 運算符返回 true。
<=>: 比較操作符(不同於=運算符),當比較的的兩個值爲 null 時返回 true。
關於 null 的條件比較運算是比較特殊的。你不能使用 = null 或 != null 在列中查找 null 值 。
在 mysql 中,null 值與任何其它值的比較(即使是 null)永遠返回 false,即 null = null 返回false 。
第5課 高級數據過濾
5.1.3 組合where子句
- OR操作符和AND操作符。
select prod_name, prod_price, vend_id from products where vend_id = '1001' OR vend_id = '1005' and prod_price >= 10;
結果:
prod_name | prod_price | vend_id |
---|---|---|
.5 ton anvil | 5.99 | 1001 |
1 ton anvil | 9.99 | 1001 |
2 ton anvil | 14.99 | 1001 |
JetPack 1000 | 35.00 | 1005 |
JetPack 2000 | 55.00 | 1005 |
分析:
OR操作符和AND操作符優先級不同。AND操作符的優先級 > OR操作符的優先級。所以上面的sql變成了:
select prod_name, prod_price, vend_id from products where vend_id = '1001' OR (vend_id = '1005' and prod_price >= 10 );
5.2 IN操作符
- select prod_name, prod_price, vend_id from products where vend_id in ('1001', '1003') order by prod_price DESC;
IN操作符的優點
- IN操作符一般比一組OR操作符更快
- IN最大的優點是:可以包含其他SELECT語句,能夠動態的建立WHERE子句,如下:
select a.* from student a join score b on a.s_id=b.s_id where b.c_id in(select c_id from course where t_id =(select t_id from teacher where t_name = '張三'));
5.3 NOT操作符
Not操作符用作否定其後所跟的任何條件。
- select * from products where Not vend_id = 1001 and prod_name = 'Safe';
prod_id | vend_id | prod_name | prod_price | prod_desc |
---|---|---|---|---|
SAFE | 1003 | Safe | 50.00 | Safe with combination lock |
注:Not在這裏只能作用與vend_id.
第6課 使用通配符進行過濾
6.1.1 百分號(%)通配符
在搜索串中,%表示任何字符出現任意次數。代表搜索模式中給定位置0個,1個,多個字符。排除匹配NULL的行。
- select prod_id, prod_name from products where prod_name like 'Jet%';
6.1.2 下劃線()通配符
在搜索串中,下劃線()只匹配單個字符,而不是多個字符。只能是一個字符。
- select prod_id, prod_name from products where prod_name like 'JetPack _000';
6.1.3 方括號([])通配符
只有微軟的Access和SQL server支持。
6.2 使用通配符的技巧
- 要知道,使用通配符可能比其他的搜索耗費更長的時間,對數據庫的壓力更大。
- 不要過度使用通配符,在其他操作符能達到效果的情況下,儘量不要使用通配符。
- 儘量不要把通配符放在搜索模式的開始處,把通配符置於開始處,搜索起來最慢的。
第7課 創建計算字段
7.1 計算字段
計算字段是運行時在SELECT語句內創建的。不同於數據庫中表的列
7.2 拼接字段
將表中的列數據,拼接到一起。將值聯結在一起(將一個值附加到另一個值), 構成單個值。如:prod_name(prod_price).
拼接的操作符:
1. Access和SQL Server使用+號
2. DB2、Oracle、PostgreSQL、SQLite和Open Office Base使用||
3. MySQL和MariaDB中,必須使用特殊的函數。eg: concat(prod_name, '(', prod_price, ')')
Trim函數
1. RTRIM(String)函數去掉字符串右邊的空格。
2. LTRIM(String)函數去掉字符串左邊的空格。
3. TRIM(String)函數去掉字符串左邊和右邊空格。
As別名。重新爲列起一個新的名字。
1. select concat(prod_name, '(', vend_id, ')') as price_info from products;
7.3 執行算術計算
算術運算符:加,減,乘,除
計算商品共賣出多少錢
1. select prod_id, quantity, item_price, quantity * item_price as expanded_price from orderitems where order_num = 20005;
第8課 使用數據處理函數
8.1 函數
SQL中函數,各個DBMS所支持的都不同,如果使用過多的函數,可能會帶來可移植問題。
8.2 使用函數
大部分SQL實現支持以下類型的函數
1. 用於處理文本字符串(如刪除,填充值,轉換大小寫等)的文本函數。
2. 用於在數值數據上進行的算術操作(如返回絕對值,進行代數運算)的數值函數。
3. 用於處理日期和時間值,並從這些值中提取特定成分(如返回兩個日期之差,檢查日期有效性)的日期和時間函數。
4. 返回DBMS正使用的特殊信息(如返回用戶登錄信息)的系統函數。
8.2.1 文本處理函數
常見的文本處理函數
函數 | 說明 |
---|---|
LEFT()(或使用子字符串函數) | 返回字符串左邊的字符 |
RIGHT()(或使用子字符串函數) | 返回字符串右邊的字符 |
LOWER()(Access使用LCASE()) | 將字符串轉換爲小寫 |
UPPER()(Access使用UCASE()) | 將字符串轉換爲大寫 |
LTRIM() | 去掉字符串左邊的空格 |
RTRIM() | 去掉字符串右邊的空格 |
TRIM()、去掉字符串左邊和右邊的空格 | |
SOUNDEX() | 返回字符串的SOUNDEX值(讀音相同) |
LENGTH()(也使用DATALENGTH()或LEN()) | 返回字符串長度 |
解釋文本處理函數:SOUNDEX()
SOUNDEX()函數是一種和根據讀音相同來比較的
1. SELECT cust_name, cust_contact FROM Customers WHERE SOUNDEX(cust_contact) = SOUNDEX('Michael Green');
8.2.2 日期和時間處理函數
非常遺憾的是:日期和時間處理函數在SQL實現中差別很大,可移植性非常差。所以,關於具體DBMS支持的日期-時間處理函數,請參閱相應的文檔。
8.2.3 數值處理函數
數值處理函數僅處理數值數據,這些函數一般主要用於代數、三角或幾何運算。數值處理函數在SQL差別不大。
函數 | 說明 |
---|---|
ABS() | 返回一個數的絕對值 |
COS() | 返回一個角度的餘弦 |
EXP() | 返回一個數的指數值 |
PI() | 返回圓周率 |
SIN() | 返回一個角度的正弦 |
SQRT() | 返回一個數的平方根 |
TAN() | 返回一個角度的正切 |
第9課 彙總數據
9.1 聚集函數
函數 | 說明 |
---|---|
AVG() | 返回某列的平均值 |
COUNT() | 返回某列的行數 |
MAX() | 返回某列的最大值 |
MIN() | 返回某列的最小值 |
SUM() | 返回某列值之和 |
9.1.1 AVG()函數
AVG函數計算表中列的平均值。AVG()只能用來確定特定數值列的平均值.AVG函數忽略列值爲NULL的行。
- select avg(prod_price) as avg_price from products;
9.1.2 COUNT()函數
COUNT函數有兩種實現方式:
1. 使用count(*),對錶中行的數目進行計數。無論是空值(NULL)或非空值。
2. 使用count(columnName)對錶特定列具有值進行計數,忽略NULL值。
3. select count(vend_state) from vendors;語句忽略NULL值。
9.1.3 MAX()函數
MAX()返回指定列中的最大值。
- select max(prod_price) as max_price from products;
9.1.4 MIN()函數
MIN()的功能正好與MAX()功能相反,它返回指定列的最小值。
9.1.5 SUM()函數
SUM()用來返回指定列值的和(總計)。
- select sum(item_price) as sum_price from orderitems where order_num = 20005;
- select sum(item_price*quantity) as total_price from orderitems where order_num = 20005;
注: 利用標準的算術運算符,所有的聚集函數都可以執行多個列上的計算。
9.2 聚集不同的值
使用關鍵字: DISTINCT關鍵字,過濾相同的值。
- select avg(distinct prod_price) as avg_price from products where vend_id = 'DLL01';
9.3 組合聚集函數
select 語句可以根據需要包含多個聚集函數。
- select count(*) as num_items, min(prod_price) as min_price, max(prod_price) as max_price, sum(prod_price) as sum_price from products;
第10課 分組數據
將數據分組,使用Group by子句和Having子句。
10.1 數據分組
目前爲止的所有計算都是在表的所有數據或匹配特定的WHERE子句的數據上進行的。沒有對應的分組概念。
- select count(*) as num_prods from products where vend_id = 'DLL01';
如果查詢每個供應商提供的商品數,怎麼查?答:需要使用分組,Group by子句和Having子句
10.2 創建分組
分組是使用select語句的Group by實現的。
- select vend_id, count(*) num_prods from products group by vend_id;
使用group by子句分組數據,然後對每個組而不是整個結果集進行聚集。
使用GROUP BY子句前,需要了解一些重要的規定:
1. GROUP BY子句可以包含任意數目的列,因而可以對分組進行嵌套,更細緻的進行分組。
2. GROUP BY子句嵌套了分組,數據將在最後指定的分組上進行彙總。
3. GROUP BY子句中列出的每一列必須是檢索列或有效的表達式。如果在SELECT中使用表達式,則必須在GROUP BY子句中指定相同的表達式。不能使用別名。
4. 大多數SQL實現不允許GROUP BY列帶有長度可變的數據類型。
5. 除聚集計算語句外,SELECT語句中的每一列都必須在GROUP BY子句中給出。
6. 如果分組列中包含具有NULL值的行,則NULL將作爲一個分組返回。如果列中有多行NULL值,它們將分爲一組。
7. GROUP BY子句必須出現在WHERE子句之後,Order by子句之前。
10.3 過濾分組
Group by新建分組,使用Having子句過濾分組。如:查詢至少有兩個訂單的顧客。
Where 子句和Having 子句的區別:
1. Where子句過濾的是行,而Having子句過濾的是分組。
2. Having子句可以替代Where子句,但是不建議這樣做。
- select vend_id, count() as num_prods from products where prod_price >= 4 group by vend_id having count() > 2;
分析:首先,where語句先選出價格大於4的商品,然後按照vend_id來進行分組,再對分組進行過濾。
10.4 分組和排序
Order by | Group by |
---|---|
對產生的輸出排序 | 對行分組,但輸出可能不是分組的順序 |
任意列都可以使用 | 只可能使用選擇列或表達式列,而且必須使用每個選擇列表達式 |
不一定需要 | 如果與聚集函數一起使用列(或表達式),則必須使用 |
語句的末尾 | 一般在join和where後面 |
一般使用GROUP BY子句後,也應該使用ORDER BY子句。
10.5 Select子句的順序
子句 | 說明 | 是否必須使用 |
---|---|---|
SELECT | 要返回的列或表達式 | 是 |
FROM | 從中檢索數據的表 | 僅在從表選擇數據時使用 |
WHERE | 行級過濾 | 否 |
GROUP BY | 分組說明 | 僅在按組計算聚集時使用 |
HAVING | 組級過濾 | 否 |
ORDER BY | 輸出排序順序 | 否 |
第11課 使用子查詢
11.2 利用子查詢進行過濾
假如需要列出訂購物品RGAN01的所有顧客,應該怎樣檢索?
1. 從訂單詳情表(OrderItems)中查詢訂購物品GRANO1的所有訂單編號。
2. 根據訂單編號,從表(Orders)中查詢顧客ID
3. 根據顧客ID,從表(Customers)查詢顧客信息。
select cust_name, cust_contact from customers
where cust_id IN (select cust_id from Order
where order_num IN (select order_num from OrderItems
where prod_id = 'GRANO1'));
作爲子查詢的Select語句只能查詢單個列(cust_id、order_num)。企圖查詢多個列,是錯誤的。
11.3 作爲計算字段使用子查詢
假如需要顯示Customers表中每個顧客的訂單總數,應該怎樣寫?
1. 從Customers表中檢索顧客列表。
2. 對於檢索的每個顧客,統計在Orders表中的數目。
select cust_name, cust_state,
(select count(*) from Orders
where Orders.cust_id = Customers.cust_id) AS orders
from Customers order by cust_name;
該子查詢檢索到每個顧客執行一次。
第12課 聯結表
12.1.1 關係表
關係表的設計就是把信息分成多個表,一類數據一個表。各個表通過共同的值進行關聯。
12.2 創建聯結
當from子句後接多個表時候,表示聯結產生了。select子句後面所接的字段,分別來自於兩個表中。
1. select vend_name, prod_name, vend_city, vendors.vend_id from vendors, products where vendors.vend_id = products.vend_id;
如果沒有Where子句,那麼返回結果就是笛卡爾積。
三者是等價的
select a.*,b.c_id,b.s_score from student a inner join score b on a.s_id=b.s_id;
select a.*,b.c_id,b.s_score from student a join score b on a.s_id=b.s_id;
select a.*,b.c_id,b.s_score from student a,score b where a.s_id=b.s_id;
12.2.3 聯結多個表
select prod_name, vend_name, prod_price, quantity from OrderItems, Products, Vendors
where Products.vend_id = Vendors.vend_id
And OrderItems.prod_id = Products.prod_id
And order_num = 20007;
第13課 創建高級聯結
13.1 使用表別名
使用表別名優點:
1. 縮短SQL語句
2. 允許在一條select語句中多次使用相同的表
select cust_name, cust_contact 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'
13.2 使用不同類型的聯結
四種聯結: 1. 內聯結或等值聯結, 2. 自聯結(self-join), 3. 自然聯結(natural join), 4. 外聯結(outer join)。
13.2.1 自聯結
問:查詢與Y Lee同一公司的所有顧客。
1. 使用子查詢
select cust_name, cust_address from customers where cust_name = (select cust_name from customers where cust_contact = 'Y Lee')
2. 使用自聯結
select C1.cust_name, C2.cust_address from customers as C1, customers as C2 where C1.cust_name = C2.cust_name and C1.cust_contact = 'Y Lee'
用自聯結而不用子查詢:
1. 許多DBMS處理聯結遠比處理子查詢快得多。
13.2.2 自然聯結
13.2.3 外聯結
許多聯結將一個表中的行和另一個表中的行相關聯,但有時候需要包含沒有關聯行的那些行。如,以下工作:
1. 對每個顧客訂單進行計數,包括至今尚未下訂單的顧客。
2. 列出所有產品以及訂購數量,包括沒人訂購的產品。
上述舉例,包括了那些相關表中沒有關聯的行。這種聯結稱爲外聯結。
檢索所有顧客及其訂單
1. 內聯結(inner join):
select Customers.cust_id, Orders.order_num from Customers inner join Orders on Customers.cust_id = Orders.cust_id;
2. 外聯結(left 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是從左邊的表(Customers)中選擇行,所以如果右表沒有對應的id則補充。要注意on後面的表Customers和Orders順序。
3. 外聯結(right outer join)
select Customers.cust_id, Orders.order_num from Customers right outer join Orders on Orders.cust_id = Customers.cust_id;
4. 全外聯結(full outer join)
select Customers.cust_id, Orders.order_num from Orders full out join Customers
on Orders.cust_id = Customers.cust_id;
兩個表的行的最大集合。
參考 https://www.cnblogs.com/dinglinyong/p/6656315.html
13.3 使用帶聚集函數的聯結
檢索所有顧客及每個顧客所下的訂單數
select Customers.cust_id, count(Orders.order_num) AS num_ord
from Customers inner join Orders on Customers.cust_id = Orders.cust_id
group by Customers.cust_id;
13.4 使用聯結和聯結條件
聯結和聯結的使用要點:
1. 注意使用的聯結類型。有內聯結,外聯結等
2. 聯結語法每個DBMS可能不一樣。
3. 保證使用正確的聯結條件,否則返回不正確的數據。
4. 應該總是使用聯結條件,否則會得到笛卡爾積。
5. 在一個聯結中可以包含多個表,甚至可以對每個聯結采用不同的聯結類型。雖然這樣做是合法的,一般也很有用,但應該在一起測試它們 前分別測試每個聯結。這會使故障排除更爲簡單。
第14課 組合查詢
利用UNION操作符將多條Select語句合成一個結果集。
14.1 組合查詢
SQL 允許執行多條查詢語句(多條Select語句),並將結果作爲一個查詢結果集返回。
主要有兩種情況需要使用組合查詢:
1. 在一個查詢中,從不同的表返回結構數據。
2. 對一個表執行多個查詢,按一個查詢返回數據。
注:一般多個Where子句的Select語句都可以作爲一個組合查詢。也就是說將Where子句拆分開來。
14.2 創建組合查詢
用操作符UNION操作符組合多條Select語句,將他們的結果組合成一個結果集。
14.2.1 使用UNION操作符
查詢Illinois、Indiana和Michigan等美國幾個州的所有顧客的報表,和不管位於哪個州的所有的Fun4All
1. 使用UNION操作符查詢。
select cust_name, cust_contact, cust_email from Customers
where cust_state in ('Illinois','Indiana','Michigan')
UNION
select cust_name, cust_contact, cust_email from Customers
where cust_name = 'Fun4All';
2. 使用Where子句
select cust_name, cust_contact, cust_email from Customers
where cust_state in ('Illinois','Indiana','Michigan') or cust_name = 'Fun4All'
Union和Where子句比較:
1. 對於較複雜的過濾條件,或者從多個表(而不是一個表)中檢索數據的情形,使用UNION可能會使處理更簡單。
2. 多數DBMS使用內部查詢優化程序,使用Union關鍵字會在內部組合它們,所以性能幾乎無差別。但使用Union操作符也請注意下性能問題。
14.2.2 UNION規則
Union非常好用,但使用組合前請注意下以下規則:
1. UNION必須由兩條或兩條以上的SELECT語句組成,語句之間用關鍵字UNION分隔。
2. UNION每次查詢必須包含相同的列,表達式,聚集函數。(各個列不需要以相同的次序列出)。
3. 列數據類型必須兼容:類型不必完全相同,但必須是DBMS可以隱含轉換的類型。
14.2.3 包含或取消重複的行
UNION從查詢結果集中自動去除了重複的行。
使用關鍵字:Union All的會返回所有的匹配行(不進行去除重複的行)。
Union All操作符是Where不能替代的。
14.2.4 對組合查詢結果排序
用Union組合查詢時,只能使用一條Order by子句,它必須位於最後一條Select語句。
- select cust_name, cust_contact, cust_id from customers
where cust_state in ('MI', 'OH')
union
select cust_name, cust_contact, cust_id from customers
where cust_contact = 'E Fudd'
order by cust_id;
注意:union組合查詢中order by子句的列必須在select後面有。且order by必須在語句最後,對整個結果集進行排序。
14.2.5 sql執行順序總結
sql 不同於與其他編程語言的最明顯特徵是處理代碼的順序。在大數編程語言中,代碼按編碼順序被處理,但是在sql語言中,第一個被處理的子句是from子句,儘管select語句第一個出現,但是幾乎總是最後被處理。
每個步驟都會產生一個虛擬表,該虛擬表被用作下一個步驟的輸入。這些虛擬表對調用者(客戶端應用程序或者外部查詢)不可用。只是最後一步生成的表纔會返回給調用者。如果沒有在查詢中指定某一子句,將跳過相應的步驟。下面是對應用於sql server 2000和sql server 2005的各個邏輯步驟的簡單描述。
(8)select (9)distinct (11)<top num> <select list>
(1)from [left_table]
(3)<join_type> join <right_table>
(2)on <join_condition>
(4)where <where_condition>
(5)group by <group_by_list>
(6)with <cube | rollup>
(7)having <having_condition>
(10)order by <order_by_list>
邏輯查詢處理階段簡介:
from:對from子句中的前兩個表執行笛卡爾積(cartesian product)(交叉聯接),生成虛擬表vt1
join on:對vt1應用on篩選器。只有那些使<join_condition>爲真的行才被插入vt2。join分爲cross join、inner join、[left join、right join,full join]
outer(join):如果指定了outer join(相對於cross join 或(inner join),保留表(preserved table:左外部聯接把左表標記爲保留表,右外部聯接把右表標記爲保留表,完全外部聯接把兩個表都標記爲保留表)中未找到匹配的行將作爲外部行添加到 vt2,生成vt3.如果from子句包含兩個以上的表,則對上一個聯接生成的結果表和下一個表重複執行步驟1到步驟3,直到處理完所有的表爲止。
where:對vt3應用where篩選器。只有使<where_condition>爲true的行才被插入vt4.和join中的on篩選類似,只是比on篩選器執行的晚.
group by:按group by子句中的列列表對vt4中的行分組,生成vt5.
cube|rollup:把超組(suppergroups)插入vt5,生成vt6.
having:對vt6應用having篩選器。只有使<having_condition>爲true的組纔會被插入vt7.過程和on、where類似,只能用在group by 之後。
select:處理select列表,產生vt8.
distinct:將重複的行從vt8中移除,產生vt9.
order by:將vt9中的行按order by 子句中的列列表排序,生成遊標(vc10).
limit/top:從vc10的開始處選擇指定數量或比例的行,生成表vt11,並返回調用者。
標準的 sql 的解析順序爲:
(0).from 子句, 組裝來自不同數據源的數據
(1).join on 拼接多個表
(2).where 子句, 基於指定的條件對記錄進行篩選
(3).group by 子句, 將數據劃分爲多個分組
(4).使用聚合函數進行計算
(5).使用 having 子句篩選分組
(6).計算所有的表達式
(7).使用 order by 對結果集進行排序
舉例說明:
在學生成績表中 (暫記爲 tb_grade), 把 "考生姓名"內容不爲空的記錄按照 "考生姓名" 分組, 並且篩選分組結果, 選出 "總成績" 大於 600 分的.
標準順序的 sql 語句爲:
select 考生姓名, max(總成績) as max總成績
from tb_grade
where 考生姓名 is not null
group by 考生姓名
having max(總成績) > 600
order by max總成績
在上面的示例中 sql 語句的執行順序如下:
(1). 首先執行 from 子句, 從 tb_grade 表組裝數據源的數據
(2). 執行 where 子句, 篩選 tb_grade 表中所有數據不爲 null 的數據
(3). 執行 group by 子句, 把 tb_grade 表按 "學生姓名" 列進行分組
(4). 計算 max() 聚集函數, 按 "總成績" 求出總成績中最大的一些數值
(5). 執行 having 子句, 篩選課程的總成績大於 600 分的.
(7). 執行 order by 子句, 把最後的結果按 "max 成績" 進行排序.
重點注意:
where和having的區別,
join需要注意用on,
like、=、is null的區別 還有null與空格的區別
order by的侷限
group by如何在count等命令下分組
第15課 插入數據
利用SQL的INSERT語句將數據插入表中。
15.1.1 插入完整的行
使用insert語句時,請在表名括號內明確給定列名。
1. insert into Customers(cust_id,cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES
('1000000006','Toy Land','123 Any Street','New York','NY','11111','USA',NULL, NULL);
15.1.3 插入檢索出的數據
將Select語句的查詢結果插入到表中。顧名思義,它是由一條INSERT語句和一條SELECT語句組成的。
insert into
Customers(cust_id, cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country)
select
cust_id,cust_contact,cust_email,cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country
from CustNew;
說明:將select語句查詢出來的結果,插入到表Customers中.
注意:
1. insert 和select不一定要求列名匹配。它使用的是列的位置,因此SELECT中的第一列(不管其列名)將用來填充表列中指定的第一列,第二列將用來填充表列中指定的第二列。
2. insert 通常只插入一行。但insert select是個例外,它可以用一條insert插入多行,不管select語句返回對少條語句,都會被插入到表中。
15.2 從一個表複製到另一個表
select into將數據複製到一個新表中。
insert select與select into區別:
1. insert select是導出數據,先select出結果,然後插入到表中。select into是導入數據。
select * into CustCopy from customers;
創建一個名爲CustCopy的新表。然後將整個customers表內容複製到表CustCopy中。
Mysql中語法是:
create table CustCopy AS select * from Customers;
使用select into注意點:
1. 任何select選項和子句都可以使用,包括where和order by。
2. 可利用聯結從多個表插入數據(Mysql中未測試通過).
3. 不管從多少個表中檢索數據,數據都只能插入到一個表中。
第16課 更新和刪除數據
16.1 更新數據
update語句更新表中的數據。
- update Customers set cust_contact = 'Sam Roberts',cust_email = '[email protected]' where cust_id = '10000006';
注意:update語句可能更新多個值。
16.2 刪除數據
delete語句刪除表中的數據。
- delete from Customers where cust_id = '10000006'
刪除時外鍵考慮:
1. 使用delete語句刪除數據時,可能會有外鍵的影響。比如:我要刪除Products表中某個商品,但是該商品cust_id在訂單表中有記錄,作爲訂單表的外鍵。那麼刪除會失敗。
16.3 更新和刪除的指導原則
- 除非確實刪除所有行或更新所有行,否則絕不能不使用where語句。
- 保證每個表都要有主鍵,儘可能像where子句那樣使用它。
- 在update和delete語句使用where子句前,應該先用select進行測試,保證過濾條件是正確無誤的。
- 使用強制實施引用完整性的數據庫,這樣DBMS將不允許刪除其數據與其他表相關聯的行。
第17課 創建和操縱表
該課主要講解:創建,更改和刪除表的基本知識。表的創建是很有學問的,本書中的內容並不豐富還需要查一些其他資料。
17.1.1 表創建基礎
利用create table創建表,必須給出下列信息:
1. 新表的名字,在關鍵字create table後給出.
2. 表列的名字和定義,用逗號隔開。
3. 有的DBMS還要指定表的位置。
CREATE TABLE IF NOT EXISTS `runoob_tbl`(
`runoob_id` INT UNSIGNED AUTO_INCREMENT,
`runoob_title` VARCHAR(100) NOT NULL,
`runoob_author` VARCHAR(40) NOT NULL,
`submission_date` DATE,
PRIMARY KEY ( `runoob_id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
實例解析:
如果你不想字段爲 NULL 可以設置字段的屬性爲 NOT NULL, 在操作數據庫時如果輸入該字段的數據爲NULL ,就會報錯。
AUTO_INCREMENT定義列爲自增的屬性,一般用於主鍵,數值會自動加1。
PRIMARY KEY關鍵字用於定義列爲主鍵。 您可以使用多列來定義主鍵,列間以逗號分隔。
ENGINE 設置存儲引擎,CHARSET 設置編碼。
17.1.2 使用Null
創建表的時候,指定表的列爲Not null,則表示,以後執行insert語句,該列必須有值,不接受null。
17.1.3 指定默認值
創建表的時候,可以爲表的列提供默認值。
- create table OrderItems
(
order_num INTEGER Not null,
order_item INTEGER Not null,
prod_id CHAR(10) Not null,
quantity INTEGER Not null default 1,
item_price DECIMAL(8,2) not null
);
17.2 更新表
使用alter table時,請考慮下列的事:
1. 理想情況下,不要再表包含數據時對其進行更新。應該在表的設計過程中充分烤爐未來可能。
2. 所有的DBMS都允許給現有的表增加列,不過對所增加列的數據類型(以及NULL和Default的使用)有所限制.
3. 許多DBMS不允許刪除或更改表中的列.
- alter table Vendors add vend_phone CHAR(20);
複雜的表結構更改一般需要手動刪除過程,它涉及以下步驟:
1. 用新的列布局創建一個新表;
2. 使用INSERT SELECT語句從舊錶複製數據到新表。有必要的話,可以使用轉換函數和計算字段;
3. 檢驗包含所需數據的新表;
4. 重命名舊錶(如果確定,可以刪除它);
5. 用舊錶原來的名字重命名新表;
6. 根據需要,重新創建觸發器、存儲過程、索引和外鍵
17.3 刪除表
- drop table Customers;
注意:刪除表不可撤銷。請慎重
17.4 重命名錶
每個DBMS對錶重命名的支持有所不同,具體要參考具體的DBMS文檔.
第18課 使用視圖
18.1 視圖
視圖是虛擬的表。與包含數據的表不一樣,視圖只包含使用時動態檢索數據的查詢。
理解視圖的最好方法是看例子.
select cust_name, cust_contact from Customers, Orders, OrderItems
where Customers.cust_id = Orders.cust_id
and OrderItems.order_num = Orders.order_num
and prod_id = 'RGAN01';
該句sql檢索訂購了某種商品的顧客。任何需要這個數據的人必須理解這些表與表之間的關係。
假如將整個查詢包裝成一個名爲ProductsCustomers的虛擬表。那麼sql可以簡化爲:
select cust_name, cust_contact from ProductCustomers where prod_id = 'RGANO1';
總結:視圖不包含任何的列或數據,包含的是一個查詢。
18.1.1 爲什麼使用視圖
視圖的常見使用場景:
1. 重用SQL語句。
2. 簡化複製的SQL操作。在編寫查詢後,可以方便的使用它,而不必知道具體的細節。
3. 使用表的一部分,而不是整個表。
4. 保護數據。可以授予用戶訪問表的特定部分,而不是表的全部權限。
5. 更改數據格式和表示。視圖可返回與底層表的表示和格式不同的數據。
創建視圖後,可以用表相同的方式去使用它們。可以對視圖執行select操作,過濾和排序數據,將視圖聯結到其他視圖或表等。
再次強調:視圖只是包含了動態檢索數據的查詢。
18.1.2 視圖的規則與限制
不同的DBMS中視圖的限制和規則可能不同,具體請參考文檔。
視圖的創建和使用的一些最常見的規則和限制:
1. 與表一樣,視圖必須唯一命名,名字不能有衝突。
2. 對於可以創建的視圖數目沒有限制。
3. 創建視圖,必須具有足夠的訪問權限。
4. 視圖可以嵌套,即可以利用從其他視圖中檢索數據的查詢來構造視圖。所允許的嵌套層數在不同的DBMS中有所不同(嵌套視圖可能會嚴 重降低查詢的性能,因此在產品環境中使用之前,應該對其進行全面測試)。
5. 許多DBMS禁止在視圖查詢中使用ORDER BY子句。
6. 有些DBMS要求對返回的所有列進行命名,如果列是計算字段,則需要使用別名。
7. 視圖不能索引,也不能有關聯的觸發器或默認值。
8. 有些DBMS把視圖作爲只讀的查詢,這表示可以從視圖檢索數據,但不能將數據寫回底層表。
18.2 創建視圖
Create view語句來創建視圖。
18.2.1 利用視圖簡化複雜的聯結
視圖最常見的應用:隱藏複雜的SQL
create view ProductCustomers AS
select cust_name, cust_contact, prod_id
from Customers, Orders, OrderItems
where Customers.cust_id = Orders.cust_id
AND OrderItems.order_num = Orders.order_num;
然後調用sql查詢:
select cust_name, cust_contact from ProductCustomers where prod_id = 'RGANO1';
18.2.2 用視圖重新下格式化檢索的數據
視圖另一個常見的應用: 重新格式化檢索出的數據
create view VendorLocations AS
select RTRIM(vend_name) + ' (' + RTRIM(vend_country) + ')'
AS vend_title from Vendors;
在單個組合計算列中返回供應商名和位置
18.2.3 用視圖過濾不想要的數據
可以定義一個視圖:過濾沒有電子郵件地址的顧客
create view CustomerEMailList AS
select cust_id, cust_name, cust_email
from Customers where cust_email is not Null;
18.2.4 使用視圖與計算字段
在簡化計算字段的使用上,視圖也特別有用。
create view OrderItemsExpanded AS
select order_num, prod_id, quantity, item_price, quantity*item_price AS expanded_price
from OrderItems
第19課 使用存儲過程
19.1 存儲過程
1. 通俗的講,存儲過程就是類似於C的一個方法。
2. 簡單的說,存儲過程就是爲以後使用而保存一條或多條SQL語句。可以將其視爲批文件,但它的作用不僅限於批處理。
19.2 爲什麼使用存儲過程
- 存儲過程有3個優點:簡單,安全和高性能。
- 多數DBMS的存儲過程可能不同,而且存儲過程也比較複雜,難於編寫。
19.3 執行存儲過程
使用關鍵字execute來執行存儲過程
EXECUTE AddNewProduct( 'JTS01', 'Stuffed Eiffel Tower', 6.49,'Plush stuffed toy with the text");
AddNewProduct是一個存儲過程,將一個新的商品添加到Product表中。但我們發現,最重要的字段prod_id列沒有,應爲我們想統一化規格化生成對應的prod_id.
所以,該存儲過程需要做以下3件事:
1. 驗證傳遞的數據,保證所有4個參數都有值;
2. 生成用作主鍵的唯一ID;
3. 將新產品插入Products表,在合適的列中存儲生成的主鍵和傳遞的數據。
19.4 創建存儲過程
創建存儲過程,每個DBMS差別很大,具體需要參考DBMS文檔。
第20課 管理事務處理
- 使用事務處理,確保成批的SQL操作要麼完全執行,要麼完全不執行,來保證數據庫的完整性。
- 事務處理是一種機制,用來管理必須成批執行的SQL操作,保證數據庫不可能包括不完整的操作結果。
- 事務都應該具備ACID特徵。所謂ACID是Atomic(原子性),Consistent(一致性),Isolated(隔離性),Durable(持久性)四個詞的首字母所寫,
在使用事務時,需要理解幾個關鍵字:
1. 事務(transaction)指一組SQL語句.
2. 回退(rollback)指撤銷指定SQL語句的過程。
3. 提交(commit)指將未存儲的SQL語句結果寫入數據庫表。
4. 保留點(savepoint)指事務處理中設置的臨時佔位符(placeholder),可以對它發佈回退。
哪些sql語句可以回退?
答:Insert, Delete和Update語句可以回退。Select, Drop和Create語句不能回退。
20.2 控制事務處理
管理事務的關鍵在於將SQL語句組合成邏輯塊,並規定數據何時回退,何時不應該回退。
不同的DBMS實現事務處理的語法不同:
1. SQL Server
Begin Transaction
...
Commit Transaction
在這裏Begin Transaction和Commit Transaction之間的SQL必須完全執行,或完全不執行。
2. Mysql
Start Transaction
...
Commit
3. Oracle
Set Transaction
...
Commit
20.2.1 使用Rollback
SQL 使用Rollback來回退(撤銷)SQL命令
命令:delete from Orders; Rollback;
使用Delete語句,然後使用Rollback語句撤銷。該句能充分說明:在事務處理塊中,delete操作(insert操作和update操作)並不是最終的結果。
20.2.2 使用Commit
在事務處理塊中,提交必須時顯示提交。
刪除訂單12345,所以需要同時更新兩個數據庫表Orders表和OrderItems表。
1. Mysql中
Begin Transaction
delete OrderItems where order_num = 12345;
delete Orders where order_num = 12345;
Commit Transaction
2. Oracle中
Set Transaction
delete OrderItems where order_num = 12345;
delete Orders where order_num = 12345;
Commit;
上面的事務處理塊中同時更新兩個表中的記錄,事務保證了操作的一致性,不可能出現部分刪除。
20.2.3 使用保留點
保留點(savepoint)作用是:支持回退部分事務。
例如添加一個訂單,需要插入顧客信息,插入訂單信息,訂單詳情信息,但當插入訂單詳情時發生錯誤,只需要回退到插入訂單信息,不需要回退到插入顧客信息。這是就需要回退部分事務。
保留點使用:在編寫事務過程中,需要在事務處理塊中的合適位置放置佔位符。用於後面的回退。
不同的DBMS的保留點設置不同
1. Mysql
Savepoint delete1;
2. SQL Server
Save Transaction delete1;
不同的DBMS的回退保留點的方式不同
1. Mysql
Rollback to delete1;
2. SQL Server
Rollback transaction delete1;
20.3 SQL Server事務舉例
不同的DBMS可能不同,但是總體概念和流程都是相同的。
Begin Transaction
insert into Customers(cust_id, cust_name) values('1000000010', 'Toys Emporium');
save transaction StartOrder;
insert into Orders(order_num, order_date, cust_id) values(20100,'2001/12/1','1000000010');
IF @@ERROR <> 0 Rollback Transaction StartOrder;
insert into OrderItems(order_num, order_item, prod_id, quantity, item_price)
values(20100, 1, 'BR01', 100, 5.49);
IF @@ERROR <> 0 Rollback Transaction StartOrder;
insert into OrderItems(order_num, order_item, prod_id, quantity, item_price)
values(20100, 2, 'BR03', 100, 10.99);
IF @@ERROR <> 0 Rollback Transaction StartOrder;
Commit Transaction;
第21課 使用遊標
21.1 遊標
SQL檢索結果是返回一組稱爲結果集的行。但是無法從結果集中得到第一行,下一行或前10行的數據。但是大多數Web應用開發人員不使用遊標,而是根據自己的需要開發相應的功能。如:利用limit1, 10來實現分頁查詢, 或使用foreach來實現遍歷。
遊標的用途:
有時,需要在檢索出來的行中前進或後退一行或多行,就需要使用遊標。
遊標(cursor)是一個存儲在DBMS服務器上的數據庫查詢,它不是一條SELECT語句。在存儲了遊標之後,應用程序可以根據需要滾動或瀏覽數據集中的數據。
遊標在不同的DBMS中的一些共性:
1. 能夠標記遊標爲只讀,使數據能讀取,但不能更新和刪除。
2. 能控制可以執行的定向操作(向前、向後、第一、最後、絕對位置、相對位置等)。
3. 能標記某些列爲可編輯的,某些列爲不可編輯的。
4. 規定訪問範圍,使遊標對創建它的特定請求(如存儲過程)或對所有請求可訪問。
5. 指示DBMS對檢索出的數據(而不是指出表中活動數據)進行復制,使數據在遊標打開和訪問期間不變化。
21.2 使用遊標
使用遊標的幾個明確的步驟:
1. 在使用遊標前,必須定義它。這個過程實際上沒有檢索數據,它只是定義要使用的SELECT語句和遊標。
2. 一旦定義,就必須打開遊標以供使用。這個過程用前面定義的SELECT語句把數據實際檢索出來。
3. 對於填有數據的遊標,根據需要取檢索各行。
4. 在結束遊標使用時,必須關閉遊標,可能的話,釋放遊標(有賴於具體的DBMS)。
21.2.1 創建遊標
使用Declare語句創建遊標。
創建一個遊標來檢索沒有電子郵件地址的所有顧客.
1. Mysql + SQL Server
Declare CustCursor Cursor for
Select * from Customers where cust_email is null;
2. Oracle
Declare Cursor CustCursor is
Select * From Customers where cust_email is null;
21.2.2 使用遊標
遊標的使用場景並不多,該節筆記比較粗糙。
使用OPEN CURSOR語句打開遊標
1. Open Cursor CustCursor;
使用Fetch語句訪問遊標數據。
Fetch需要指出檢索哪些行,從何處檢索他們以及將他們存放於何處。
Declare Type CustCursor IS ref Cursor
Return Customers%ROWTYPE;
Declare CustRecord Customers%ROWTYPE
Begin
Open CustCursor;
Fetch CustCursor INTO CustRecord;
Close CustCursor;
End;
21.2.3 關閉遊標
1. Oracle
Close CustCursor;
2. SQL Server
Close CustCursor
Deallocate Cursor CustCursor;
第22課 高級SQL特性
22.1 約束
- 約束: 管理如何插入或處理數據庫數據的規則。
- 引用完整性(referential integrity): 利用鍵來建立從一個表到另一個表的引用
關係型數據庫,需要保證插入數據庫的數據和合法性。
例如:如果Orders表存儲訂單信息,OrderItems表存儲訂單詳細內容,應該保證OrderItems中引用的任何訂單ID都存在於Orders中。類似地,在Orders表中引用的任意顧客必須存在於Customers表中。
DBMS通過在數據庫表上施加約束來實施引用完整性.
22.1.1 主鍵
主鍵是一種特殊的約束,用來某一行的數據是唯一的,而且主鍵永不改動。
表中的列只要滿足以下條件,可用於主鍵:
1. 任意兩行的主鍵值都不相同。
2. 每行都具有一個主鍵值(即列中不允許NULL值)。
3. 包含主鍵值的列從不修改或更新。
4. 主鍵值不能重用。如果從表中刪除某一行,其主鍵值不分配給新行。
主鍵的創建:
1. Create Table
Create Table Vendors
(
vend_id CHAR(10) NOT NULL Primary Key,
vend_name CHAR(50) NOT NULL,
vend_address CHAR(50) NULL,
vend_city CHAR(50) NULL,
vend_state CHAR(5) NULL,
vend_zip CHAR(10) NULL,
vend_country CHAR(50) NULL
);
Primary Key聲明表的主鍵列
2. Alter Table
Alter Table Vendors
Add Constraint Primary Key(vend_id);
22.1.2 外鍵
外鍵是表中的一列,其值必須在另一表的主鍵列中。
外鍵是關係數據庫描述表和表之間依賴關係
1. Create Table
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)
);
2 Alter Table
Alter Table Orders
Add Constraint Foreign key (cust_id) references Customers(cust_id);
外鍵的作用:
1. 能夠幫組保證引用完整性。
2. 防止意外刪除記錄
由於顧客表Customers表中主見: cust_id,作爲訂單表Orders中的外鍵。所以如果想直接刪除顧客表中的記錄,必須保證其值已經不被訂單表中依賴。
3. 級聯刪除
Mysql支持級聯刪除特性。解釋:如果從顧客表Customers表中刪除某個顧客,那麼由於顧客表Customers表中的主見cust_id作爲了Orders表中的外鍵依賴,所以訂單表Orders中的該顧客的訂單也一併刪除。
22.1.3 唯一約束
唯一約束用來保證某一列中的數據是唯一的。它和主鍵有以下區別:
1. 表可包含多個唯一約束,但每個表只允許一個主鍵。
2. 唯一約束列可包含NULL值。
3. 唯一約束列可修改或更新。
4. 唯一約束列的值可重複使用。
5. 與主鍵不一樣,唯一約束不能用來定義外鍵。
22.1.4 檢查約束
檢查約束用來保證一列中的數據滿足一組指定的條件。檢查約束的常見用途:
1. 檢查最小或最大值。例如,防止0個物品的訂單(即使0是合法的數)。
2. 指定範圍。例如,保證發貨日期大於等於今天的日期,但不超過今天起一年後的日期。
3. 只允許特定的值。例如,在性別字段中只允許M或F。
對OrderItems表施加了檢查約束,保證所有物品的數量大於0:
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
);
檢查名爲gender的列只包含M或F
Alter Table OrderItems
Add Constraint Check (gender LIKE '[MF]')
22.2 索引
索引是利用B+等索引機制,加快查詢和排序的速度。
使用索引需要記住以下內容:
1. 索引提高檢索操作的性能,但降低了數據插入、修改和刪除的性能。因爲數據變更需要更新索引。
2. 索引數據可能要佔用大量的存儲空間。
3. 並非所有數據都適合做索引。查詢量非常大,列的數據非常多,使用使用索引。
4. 索引用於數據過濾和數據排序。如果你經常以某種特定的順序排序數據,則該數據可能適合做索引。
5. 可以在索引中定義多個列(例如,州加上城市)。這樣的索引僅在以州加城市的順序排序時有用。
所以必須唯一命名:
Create Index prod_name_index On Products(prod_name);
22.2.1 索引建立的幾大原則
組合索引的解釋:
如果創建了(state, city, zip)列作爲組合索引,索引中的數據行按照state/city/zip次序排列,
這意味着,這個索引可以被用於搜索如下所示的數據列組合:
state, city, zip
state, city
state
但是MySQL不能利用這個索引來搜索沒有包含在最左前綴的內容。例如,如果你按照city或zip來搜索,
就不會使用到這個索引。如果你按照state,和zip來搜索,該索引也是不能用於這種組合值的,但是可以利用索引來查找匹配的state從而縮小搜索的範圍。
1. 選擇唯一性索引
唯一性索引的值是唯一的,能快速的通過該索引來確定某條記錄。
2. 爲經常需要排序、分組和聯合操作的字段建立索引
經常需要Order By、Group By、Distinct和Union等操作的字段,排序操作會浪費很多時間。
3. 爲常作爲查詢條件的字段建立索引
某個字段經常用來做查詢條件,該字段的查詢速度會影響整個表的查詢速度。使用索引,可以極大加快查詢速度。
4. 最左前綴匹配原則,非常重要的原則。
mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就停止匹配,
比如state='yes' and city='wuwei' and price > 3 and name = 'ppp' 如果建立(state, city, price, name)順序的索引,
name的查詢是用不到索引的,只能使用部分索引,然後在結果集上面進行排序。如果建立(state, city , ppp, price)的索引則都可以用到,state, city, name的順序可以任意調整。
5. =和in可以亂序。
比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優化器會幫你優化成索引可以識別的形式。
但是如果建立索引(a,b,c),結果where子句是:b =2 and c=3,則索引不起作用。
6. 儘量使用數據量少的索引
如果索引的值很長,那麼查詢的速度會受到影響。
例如,對一個CHAR(100)類型的字段進行全文檢索需要的時間肯定要比對CHAR(10)類型的字段需要的時間要多。
7. 儘量使用前綴來索引
索引字段的值很長,應該採用前綴來索引。
8. 儘量選擇區分度高的列作爲索引。
數據量區分度越高,索引的比較成本會小很多。
9. 刪除不再使用或者很少使用的索引
請定期刪除不在使用的索引。
10. 限制索引的數目
使用索引需要付出代價,索引會消耗磁盤空間,對數據庫記錄的更新和刪除產生影響。
11. 索引列不能參與計算。
堅決不能將某個計算函數作爲縮影。如:from_unixtime(create_time) = ’2014-05-29’
12. 儘量的擴展索引,不要新建索引。
比如表中已經有a的索引,現在要加(a,b)的索引,那麼只需要修改原來的索引即可
22.3 觸發器
觸發器是特殊的存儲過程,可以在特定的數據庫活動發生時自動執行。
觸發器可以與特定表上的Insert, Update或Delete操作(或組合)想關聯。
如:與Orders表上的Insert操作相關聯的觸發器只在Orders表中插入行時纔會執行。
觸發器的常見用途:
1. 保證數據一致。例如,在Insert或Update操作中將所有州名轉換爲大寫。
2. 基於某個表的變動在其他表上執行活動。例如,每當更新或刪除一行時將審計跟蹤記錄寫入某個日誌表。
3. 進行額外的驗證並根據需要回退數據。例如,保證某個顧客的可用資金不超限定,如果已經超出,則阻塞插入。
4. 計算計算列的值或更新時間戳。
不同的DBMS的觸發器差距很大,請參考具體文檔.
如:創建一個觸發器,對所有Insert和Update操作,將Customers表中的cust_state列轉換爲大寫。
1. SQL Server
Create Trigger customer_state On Customers
For Insert, Update As
Update Customers Set cust_state = Upper(cust_state)
2. Oracle
Create Trigger customer_state
After Insert Or Uupdate
For Each Row
Begin
Update Customers
Set cust_state = Upper(cust_state)
Where Customers.cust_id = :OLD.cust_id
end;
22.4 數據庫安全
一般對數據保護操作有:
1. 對數據庫管理功能(創建表、更改或刪除已存在的表等)的訪問;
2. 對特定數據庫或表的訪問;
3. 訪問的類型(只讀、對特定列的訪問等);
4. 僅通過視圖或存儲過程對錶進行訪問;
5. 創建多層次的安全措施,從而允許多種基於登錄的訪問和控制;
6. 限制管理用戶賬號的能力。