SQL必知必会第4版读书笔记
SQL必知必會_4
前言
@author 魯偉林 在讀電子版<<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 5; 返回結果只有5行。
- select prod_name from products limit 5 offset 5; 返6,7,8,9,10這5行數據。
2.7 使用注釋
第3課 排序檢索數據
使用Select子句的Order by子句,根據需要檢索排序出的數據3.1 排序數據
使用Order by語句排序Select檢索出來的語句, Order by子句取一個或多個列的名字。
select prodname, prodprice from products order by prod_price;注:Order by子句, 必須是select的最后一條語句。
3.2 按多個列排序
select prodname, prodprice, prodid from products order by prodprice, prod_name;
3.3 按列位置排序
select prodname, prodprice, prod_id from products order by 2, 3;注: 1. order by 后面可以接數字,比如:2代表的是prod_price, 3代表的是prod_id。不推薦使用這種方式。
3.4 指定排序方向
ASC 升序(默認),DESC 降序。
- select prodname, prodprice, prodid from products order by prodprice DESC, prod_name;
- 如果DESC降序,必須對所有需要降序的列都要加上。
第4課 過濾數據
4.2.3 范圍值檢查
- select prodname, prodprice, prodid from products where prodprice between 4 and 10;
4.2.4 空值檢查
- select * from customers where cust_email is NULL; 空判斷過濾數據
- select * from customers where cust_email is not NULL; 非空判斷過濾數據
第5課 高級數據過濾
5.1.3 組合where子句
結果:
| .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 prodname, prodprice, vendid from products where vendid in ('1001', '1003') order by prod_price DESC;
IN操作符的優點
5.3 NOT操作符
Not操作符用作否定其后所跟的任何條件。
- select * from products where Not vendid = 1001 and prodname = 'Safe';
| SAFE | 1003 | Safe | 50.00 | Safe with combination lock |
注:Not在這里只能作用與vend_id.?
第6課 使用通配符進行過濾
6.1.1 百分號(%)通配符
在搜索串中,%表示任何字符出現任意次數。代表搜索模式中給定位置0個,1個,多個字符。排除匹配NULL的行。
- select prodid, prodname from products where prod_name like 'Jet%';
6.1.2 下劃線(_)通配符
在搜索串中,下劃線(_)只匹配單個字符,而不是多個字符。只能是一個字符。
- select prodid, prodname from products where prod_name like 'JetPack _000';
6.1.3 方括號([])通配符
只有微軟的Access和SQL server支持。
6.2 使用通配符的技巧
第7課 創建計算字段
7.1 計算字段
計算字段是運行時在SELECT語句內創建的。不同于數據庫中表的列
7.2 拼接字段
將表中的列數據,拼接到一起。將值聯結在一起(將一個值附加到另一個值), 構成單個值。如:prodname(prodprice).
拼接的操作符: 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(prodprice) as avgprice 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(prodprice) as maxprice from products;
9.1.4 MIN()函數
MIN()的功能正好與MAX()功能相反,它返回指定列的最小值。
9.1.5 SUM()函數
SUM()用來返回指定列值的和(總計)。
- select sum(itemprice) as sumprice from orderitems where order_num = 20005;
- select sum(itemprice*quantity) as totalprice from orderitems where order_num = 20005;
注: 利用標準的算術運算符,所有的聚集函數都可以執行多個列上的計算。
9.2 聚集不同的值
使用關鍵字: DISTINCT關鍵字,過濾相同的值。
- select avg(distinct prodprice) as avgprice from products where vend_id = 'DLL01';
9.3 組合聚集函數
select 語句可以根據需要包含多個聚集函數。
- select count(*) as numitems, min(prodprice) as minprice, max(prodprice) as maxprice, sum(prodprice) as sum_price from products;
第10課 分組數據
將數據分組,使用Group by子句和Having子句。
10.1 數據分組
目前為止的所有計算都是在表的所有數據或匹配特定的WHERE子句的數據上進行的。沒有對應的分組概念。
- select count(*) as numprods from products where vendid = 'DLL01';
如果查詢每個供應商提供的商品數,怎么查?答:需要使用分組,Group by子句和Having子句
10.2 創建分組
分組是使用select語句的Group by實現的。
- select vendid, count(*) numprods 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 vendid, count(*) as numprods from products where prodprice >= 4 group by vendid having count(*) > 2;
分析:首先,where語句先選出價格大于4的商品,然后按照vend_id來進行分組,再對分組進行過濾。
10.4 分組和排序
| 對產生的輸出排序 | 對行分組,但輸出可能不是分組的順序 |
| 任意列都可以使用 | 只可能使用選擇列或表達式列,而且必須使用每個選擇列表達式 |
| 不一定需要 | 如果與聚集函數一起使用列(或表達式),則必須使用 |
一般使用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 customerswhere cust_id IN (select cust_id from Orderwhere order_num IN (select order_num from OrderItemswhere prod_id = 'GRANO1'));作為子查詢的Select語句只能查詢單個列。企圖查詢多個列,是錯誤的。
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子句,那么返回結果就是笛卡爾積。12.2.3 聯結多個表
select prodname, vendname, prodprice, quantity from OrderItems, Products, Vendors where Products.vendid = Vendors.vendid And OrderItems.prodid = Products.prodid And ordernum = 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; 兩個表的行的最大集合。13.3 使用帶聚集函數的聯結
檢索所有顧客及每個顧客所下的訂單數 1. 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 custname, custcontact, custid from customers where custstate in ('MI', 'OH') union select custname, custcontact, custid from customers where custcontact = 'E Fudd' order by cust_id;
注意:union組合查詢中order by子句的列必須在select后面有。且order by必須在語句最后,對整個結果集進行排序。
第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 custcontact = 'Sam Roberts',custemail = 'sam@toyland.com' where cust_id = '10000006';
注意:update語句可能更新多個值。
16.2 刪除數據
delete語句刪除表中的數據。
- delete from Customers where cust_id = '10000006'
16.3 更新和刪除的指導原則
第17課 創建和操縱表
該課主要講解:創建,更改和刪除表的基本知識。
17.1.1 表創建基礎
利用create table創建表,必須給出下列信息: 1. 新表的名字,在關鍵字create table后給出. 2. 表列的名字和定義,用逗號隔開。 3. 有的DBMS還要指定表的位置。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), prod_desc text(1000), NULL );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);
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. 更改數據格式和表示。視圖可返回與底層表的表示和格式不同的數據。 創建視圖后,可以用表相同的方式去使用它們??梢詫σ晥D執行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語句??梢詫⑵湟暈榕募?#xff0c;但它的作用不僅限于批處理。19.2 為什么使用存儲過程
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(持久性)四個詞的首字母所寫,
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 ... Commit20.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 BeginOpen 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 約束
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. 限制管理用戶賬號的能力。總結
以上是生活随笔為你收集整理的SQL必知必会第4版读书笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c# 监听 Modern Standby
- 下一篇: 《Mysql》必知必会读书笔记