SQL必知必會

先來幾張圖

前言

@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 使用註釋
  1. 單行註釋: #
  2. 多行註釋: /. ... /

第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子句
  1. 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操作符的優點

  1. IN操作符一般比一組OR操作符更快
  2. 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 使用通配符的技巧
  1. 要知道,使用通配符可能比其他的搜索耗費更長的時間,對數據庫的壓力更大。
  2. 不要過度使用通配符,在其他操作符能達到效果的情況下,儘量不要使用通配符。
  3. 儘量不要把通配符放在搜索模式的開始處,把通配符置於開始處,搜索起來最慢的。

第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 更新和刪除的指導原則
  1. 除非確實刪除所有行或更新所有行,否則絕不能不使用where語句。
  2. 保證每個表都要有主鍵,儘可能像where子句那樣使用它。
  3. 在update和delete語句使用where子句前,應該先用select進行測試,保證過濾條件是正確無誤的。
  4. 使用強制實施引用完整性的數據庫,這樣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 爲什麼使用存儲過程
  1. 存儲過程有3個優點:簡單,安全和高性能。
  2. 多數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 約束
  1. 約束: 管理如何插入或處理數據庫數據的規則。
  2. 引用完整性(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. 限制管理用戶賬號的能力。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章