篇幅過長,恐懼者慎入!!!基礎知識,大神請繞道!!!
本節要點:
- l SQL概述
- l 學生-課程關系
- l 數據定義
- 基本表的定義、刪除與修改
- 索引的建立與刪除
- l 查詢
- 單表查詢
- 連接查詢
- 嵌套查詢
- 集合查詢
- l 數據更新
- 插入數據
- 修改數據
- 刪除數據
- l 視圖
- 定義視圖
- 查詢視圖
- 更新視圖
- 視圖的作用
SQL(Structured Query Language),即結構化查詢語言,是關系數據庫的標准語言,SQL是一個通用的、功能極強的關系數據庫語言。當前,幾乎所有的關系數據庫管理系統軟件都支持SQL。本節將主要介紹SQL。
1 SQL概述
SQL是在1974年由Boyce和Chamberlin提出的,並在IBM公司研制的關系數據庫管理系統原型System R上實現。SQL之所以能夠為用戶和業界所接受,並成為國際標准,是因為它是一個綜合的、功能極強同時又簡介易學的語言。SQL集數據查詢(Data Query)、數據操縱(Data Manipulation)、數據定義(Data Definition)和數據控制(Data Control)功能於一體。
SQL的特點:
- l 綜合統一
- l 高度非過程化
- l 面向集合的操作方式
- l 以同一種語法結構提供兩種使用方法(交互式, 嵌入式)
- l 語言簡潔,易學易用
注:SQL完成核心功能只用了下面9個動詞:
2 學生-課程關系
接下來知識的學習需要用到學生-課程的關系作為例子來講解,所以先給出3個表的關系:
- l 學生表:Student(Sno,Sname,Ssex,Sage,Sdept)
- l 課程表:Course(Cno,Cname,Cpno,Ccredit)
- l 學生選課表:SC(Sno,Cno,Grade)
注:加下划線的是關系中的主碼。
各個表中的數據示例如下(表的具體定義后續會講到,先看看表的結構和信息):
Student
學號Sno |
姓名Sname |
性別Ssex |
年齡Sage |
所在系Sdept |
200215121 |
李勇 |
男 |
20 |
CS |
200215122 |
劉晨 |
女 |
19 |
CS |
200215123 |
王敏 |
女 |
18 |
MA |
200215125 |
張立 |
男 |
19 |
IS |
Course
課程號Cno |
課程名Cname |
先行課Cpno |
學分Ccredit |
1 |
數據庫 |
5 |
4 |
2 |
數學 |
|
2 |
3 |
信息系統 |
1 |
4 |
4 |
操作系統 |
6 |
3 |
5 |
數據結構 |
7 |
4 |
6 |
數據處理 |
|
2 |
7 |
PASCAL語言 |
6 |
4 |
SC
學號Sno |
課程號Cno |
成績Grade |
200215121 |
1 |
92 |
200215121 |
2 |
85 |
200215121 |
3 |
88 |
200215122 |
2 |
90 |
200215122 |
3 |
80 |
3 數據定義
關系數據庫系統支持三級模式結構,其模式、外模式和內模式中的基本對象由表、視圖和索引,因此SQL的數據定義功能包括表定義、視圖和索引的定義,如下表是SQL的數據定義語句總結:
3.1 基本表的定義、刪除與修改
1) 定義基本表
語法:
CREATE TABLE <表名>
(<列名> <數據類型>[ <列級完整性約束條件> ]
[,<列名> <數據類型>[ <列級完整性約束>] ] …
[,<表級完整性約束> ]
);
<表名>:所要定義的基本表的名字
<列名>:組成該表的各個屬性(列)
<列級完整性約束條件>:涉及相應屬性列的完整性約束條件
<表級完整性約束條件>:涉及一個或多個屬性列的完整性約束條件
示例:
- 建立學生表Student:
CREATE TABLE Student
(Sno CHAR(5) PRIMARY KEY, /* PRIMARY KEY是完整性約束,以后講到*/
Sname CHAR(20) NOT NULL,
Ssex CHAR(1) ,
Sage INT,
Sdept CHAR(15));
- 建立一個“課程”表Course:
CREATE TABLE Course
(Cno CHAR(5) PRIMARY KEY,
Cname CHAR(20) NOT NULL,
Cpno CHAR(5) ,
Credit INT,
FOREIGN KEY Cpno REFERENCES Course(Cno));
注:說明參照表和被參照表可以是同一個。
- 建立一個“學生選課”表SC,它由學號Sno、課程號Cno,修課成績Grade組成,其中(Sno, Cno)為主碼:
CREATE TABLE SC(
Sno CHAR(5) ,
Cno CHAR(3) ,
Grade INT,
Primary key (Sno, Cno),
FOREIGN KEY (Sno) REFERENCES Student(Sno)
FOREIGN KEY (Cno) REFERENCES Course(Cno));
2) 數據類型
關系模型中一個很重要的概念是域,每一個屬性來自一個域,它的取值必須是域中的值。在SQL中域的概念用數據類型來實現,在定義表的各個屬性時需要指明其數據類型及長度。SQL提供了一些主要數據類型如下(不同的RDBMS中支持的數據類型不盡相同):
數據類型 |
含義 |
CHAR(n) |
長度為n的定長字符串 |
VARCHAR(n) |
最大長度為n的變長字符串 |
INT |
長整數(也可以寫成INTEGER) |
SMALLINT |
短整數 |
NUMBERIC(p,d) |
定點數,由p為數字(不包括符號、小數點)組成,小數后面有d位數字 |
REAL |
取決於機器精度的浮點數 |
Double Percision |
取決於機器精度的雙精度浮點數 |
FLOAT(n) |
浮點數,精度至少為n位數字 |
DATE |
日期,包含年月日,格式為YYYY-MM-DD |
TIME |
時間,包含一日的時分秒,格式為HH:MM:SS |
注:VARCHAR、NUMBERIC和DATE較常用。
3) 刪除基本表
語法:
DROP TABLE <表名> [RESTRICT|CASCADE];
RESTRICT:該表刪除是有限制的,待刪除的表不能被其他表的約束所引用,否則不能刪除;
CASCADE:刪除表的同時刪除其他約束對象。
一般默認是RESTRICT。
示例:(慎用,一旦刪除不可恢復)
刪除Student表
DROP TABLE Student RESTRICT;
4) 修改基本表
語法:
ALTER TABLE <表名>
[ ADD <新列名> <數據類型> [ 完整性約束 ] ]
[ DROP <原列名>|<完整性約束名> ]
[ALTER COLUMN <原列名> <數據類型> ];
- <表名>:要修改的基本表
- ADD子句:增加新列和新的完整性約束條件
- DROP子句:刪除指定的列或完整性約束
- ALTER COLUMN子句:用於修改指定列的數據類型
示例:
向Student表增加“入學時間”列,其數據類型為日期型:
ALTER TABLE Student ADD Scome DATE;
將年齡的數據類型由字符型(假設原來的數據類型是字符型)改為整數:
ALTER TABLE Student ALTER COLUMN Sage INT;
刪除列屬性:
ALTER TABLE Student Drop Scome;
3.2 索引的建立與刪除
假設你負責一本學生記錄表(2萬學生要近千頁). 經常有人來要求按學生名查詢某某學生信息。你如何查才能提高查詢速度?我們知道一般在文檔操作的時候就有建立學生名目錄(按拼音排序)。同樣,運用到數據庫上,可以在一列或者多列上建立索引,根據索引去查詢。相比較對整個表進行查詢,索引查詢只是選取了一列或者幾列,查詢的范圍小,查詢時數據占用的內存小。
1) 建立索引
建立索引是加快查詢速度的有效手段
語法:
CREATE INDEX <索引名>
ON <表名>(<列名 [,<列名> ]…);
示例:
為Student的sname列建立索引:
CREATE INDEX StuName ON Student(Sname);
2) 刪除索引
語法:
DROP INDEX <索引名>;
示例:刪除Student表的Stusname索引。
DROP INDEX Stusname;
4 查詢
數據庫查詢時數據庫的核心操作。SQL提供了SELECT語句進行數據庫的操作,其一般格式如下:
SELECT [ALL|DISTINCT] <目標列表達式> [,<目標列表達式>] …
FROM <表或視圖名>[,<表或視圖名> ] …
[ WHERE <條件表達式> ]
[ GROUP BY <列名1>
[ HAVING <條件表達式> ] ]
[ ORDER BY <列名2> [ ASC|DESC ] ];
- SELECT子句:指定要顯示的屬性列
- FROM子句:指定查詢對象(基本表或視圖)
- WHERE子句:指定查詢條件
- GROUP BY子句:對查詢結果按指定列的值分組,該屬性列值相等的元組為一個組。通常會在每組中作用集函數。
- HAVING短語:篩選出只有滿足指定條件的組
- ORDER BY子句:對查詢結果表按指定列值的升序或降序排序
4.1 單表查詢
單表查詢表示查詢僅涉及一個表,是一種最簡單的查詢操作:
一、選擇表中的若干列
二、選擇表中的若干元組
三、對查詢結果排序
四、使用集函數
五、對查詢結果分組
1) 查詢指定列
示例:查詢全體學生的學號與姓名。
SELECT Sno,Sname FROM Student;
示例: 查詢全體學生的姓名、學號、所在系。
SELECT Sname,Sno,Sdept FROM Student;
2) 查詢全部列
示例:查詢全體學生的詳細記錄。
SELECT Sno,Sname,Ssex,Sage,Sdept FROM Student;
或
SELECT * FROM Student;
3) 查詢經過計算的值
SELECT子句的<目標列表達式>不僅可以是表中的屬性列,也可以是表達式。
示例:查全體學生的姓名及其出生年份。
SELECT Sname,2012-SageFROM Student;
示例:查詢全體學生的姓名、出生年份和所有系,要求用小寫字母表示所有系名。
SELECT Sname,'Year of Birth: ',2012 Sage, ISLOWER(Sdept) FROM Student;
4) 使用列別名(可選)改變查詢結果的列標題
示例:SELECT Sname NAME,'Year of Birth: ' BIRTH,2012-Sage BIRTHDAY,ISLOWER(Sdept) DEPARTMENT FROM Student;
輸出結果:
NAME BIRTH BIRTHDAY DEPARTMENT
------- -------- ------- ------- --------
李勇 Year of Birth: 1986 cs
劉晨 Year of Birth: 1987 is
王名 Year of Birth: 1988 ma
張立 Year of Birth: 1987 is
5) 消除取值重復的行
- ALL查詢滿足條件的元組
SELECT ALL Sno FROM SC;
等價於
SELECT Sno FROM SC;
結果:Sno
-------
95001
95001
95001
95002
95002
- DISTINCT消除取值重復的行
SELECT DISTINCT Sno FROM SC;
結果: Sno
-------
95001
95002
注意 DISTINCT短語的作用范圍是所有目標列
例:查詢選修課程的各種成績
錯誤的寫法:
SELECT DISTINCT Cno,DISTINCT Grade FROM SC;
正確的寫法
SELECT DISTINCT Cno,Grade FROM SC;
6) 查詢滿足條件的元組
查詢滿足指定條件的元組可以通過WHERE字句實現。WHERE字句常用的查詢條件如下:
查詢條件 |
謂詞 |
比較 |
=,>,<,>=,<=,!=,<>,!>,!<;NOT+上述比較運算符 |
確定范圍 |
BETWEEN AND,NOT BETWEEN AND |
確定集合 |
IN,NOT IN |
字符匹配 |
LIKE,NOT LIKE |
空值 |
IS NULL,IS NOT NULL |
多重條件(邏輯運算) |
AND,OR,NOT |
- 比較大小
在WHERE子句的<比較條件>中使用比較運算符=,>,<,>=,<=,!= 或 <>,!>,!<,邏輯運算符NOT + 比較運算符
示例: 查詢所有年齡在20歲以下的學生姓名及其年齡。
SELECT Sname,Sage
FROM Student
WHERE Sage < 20;
或
SELECT Sname,Sage
FROM Student
WHERE NOT Sage >= 20;
- 確定范圍
使用謂詞 BETWEEN … AND …
NOT BETWEEN … AND …
示例:查詢年齡在20~23歲(包括20歲和23歲)之間的學生的姓名、系別和年齡。
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage BETWEEN 20 AND 23;
示例:查詢年齡不在20~23歲之間的學生姓名、系別和年齡。
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage NOT BETWEEN 20 AND 23;
- 確定集合
使用謂詞IN (值表)、NOT IN (值表)。值表:用逗號分隔的一組取值
示例:
查詢信息系(IS)、數學系(MA)和計算機科學系(CS)學生的姓名和性別。
SELECT Sname,Ssex
FROM Student
WHERE Sdept IN ( 'IS','MA','CS' );
查詢既不是信息系、數學系,也不是計算機科學系的學生的姓名和性別。
SELECT Sname,Ssex
FROM Student
WHERE Sdept NOT IN ( 'IS','MA','CS' );
- 字符串匹配
謂詞like可以用來進行字符串的匹配。其一般語法格式如下:
[NOT] LIKE ‘<匹配串>’ [ESCAPE ‘ <換碼字符>’]
其中<匹配串>用來指定匹配模板,可以是一個完整的字符串,也可以含有通配符%和_。其中:
-
- % (百分號) 代表任意長度(長度可以為0)的字符串。例:a%b表示以a開頭,以b結尾的任意長度的字符串。如acb,addgb,ab 等都滿足該匹配串
- _ (下橫線) 代表任意單個字符。例:a_b表示以a開頭,以b結尾的長度為3的任意字符串。如acb,afb等都滿足該匹配串
a 匹配模板為固定字符串
示例:查詢學號為95001的學生的詳細情況。
SELECT *
FROM Student
WHERE Sno LIKE '95001';
等價於
SELECT *
FROM Student
WHERE Sno = '95001';
b 匹配模板為含通配符的字符串
示例: 查詢所有姓劉學生的姓名、學號和性別。
SELECT Sname,Sno,Ssex
FROM Student
WHERE Sname LIKE ‘劉%’;
示例: 查詢姓"歐陽"且全名為三個漢字的學生的姓名。
SELECT Sname
FROM Student
WHERE Sname LIKE '歐陽__';
示例: 查詢名字中第2個字為"陽"字的學生的姓名和學號。
SELECT Sname,Sno
FROM Student
WHERE Sname LIKE '__陽%';
示例: 查詢所有不姓劉的學生姓名。
SELECT Sname,Sno,Ssex
FROM Student
WHERE Sname NOT LIKE '劉%';
ESCAPE 短語:當用戶要查詢的字符串本身就含有 % 或 _ 時,要使用ESCAPE '<換碼字符>' 短語對通配符進行轉義。
使用換碼字符將通配符轉義為普通字符
示例:查詢DB_Design課程的課程號和學分。
SELECT Cno,Ccredit
FROM Course
WHERE Cname LIKE 'DB\_Design' ESCAPE '\'
示例:查詢以"DB_"開頭,且倒數第3個字符為 i的課程的詳細情況。
SELECT *
FROM Course
WHERE Cname LIKE 'DB\_%i_ _' ESCAPE ' \ ';
- 涉及空值的查詢
使用謂詞 IS NULL 或 IS NOT NULL。“IS NULL” 不能用 “= NULL” 代替。
示例:某些學生選修課程后沒有參加考試,所以有選課記錄,但沒有考試成績。查詢缺少成績的學生的學號和相應的課程號。
SELECT Sno,Cno
FROM SC
WHERE Grade IS NULL;
示例:查所有有成績的學生學號和課程號。
SELECT Sno,Cno
FROM SC
WHERE Grade IS NOT NULL;
- 多重條件查詢
用邏輯運算符AND和 OR來聯結多個查詢條件。AND的優先級高於OR,可以用括號改變優先級。
可用來實現多種其他謂詞[NOT] IN和 [NOT] BETWEEN … AND …
示例:查詢計算機系年齡在20歲以下的學生姓名。
SELECT Sname
FROM Student
WHERE Sdept= 'CS' AND Sage<20;
示例:查詢信息系(IS)、數學系(MA)和計算機科學系(CS)學生的姓名和性別。
SELECT Sname,Ssex
FROM Student
WHERE Sdept IN ( 'IS','MA','CS' )
等價於:
SELECT Sname,Ssex
FROM Student
WHERE Sdept= ' IS ' OR Sdept= ' MA' OR Sdept= ' CS
示例:查詢年齡在20~23歲(包括20歲和23歲)之間的學生的姓名、系別和年齡。
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage BETWEEN 20 AND 23;
等價於:
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage>=20 AND Sage<=23;
7) 對查詢結果排序
排序使用ORDER BY子句,可以按一個或多個屬性列排序,升序關鍵字是ASC,降序關鍵字是DESC,缺省值為升序。當排序列含空值時,ASC:排序列為空值的元組最后顯示;DESC:排序列為空值的元組最先顯示 。
示例:查詢選修了3號課程的學生的學號及其成績,查詢結果按分數降序排列。
SELECT Sno,Grade
FROM SC
WHERE Cno= ' 3 '
ORDER BY Grade DESC;
示例:查詢全體學生情況,查詢結果按所在系的系號升序排列,同一系中的學生按年齡降序排列。
SELECT *
FROM Student
ORDER BY Sdept,Sage DESC;
8) 使用集函數
1行計數
(1)COUNT([DISTINCT|ALL] *):對每行計數;DISTINCT短語表示在計算時要取消指定列中的重復值;ALL短語表示不取消重復值,ALL為缺省值
(2)COUNT([DISTINCT|ALL] <列名>):對<列名>非空的行計數
示例: 查詢學生總人數。
SELECT COUNT(*)
FROM Student;
示例: 查詢選修了課程的學生人數。
SELECT COUNT(DISTINCT Sno)
FROM SC;
注:對Sno非空的行,排除重復Sno計數。以避免重復計算學生人數
有什么區別?
SELECT COUNT(*) FROM SC;
SELECT COUNT(Grade) FROM SC;
有什么區別?
SELECT COUNT(SNO) FROM SC;
SELECT COUNT(DISTINCT SNO) FROM SC;
2.計算總和(對非空列)
SUM([DISTINCT|ALL] <列名>)
3.計算平均值(對非空列)
AVG([DISTINCT|ALL] <列名>)
示例:計算1號課程的學生平均成績。
SELECT AVG(Grade)
FROM SC
WHERE Cno= ' 1 ';
4.求最大值(對非空列)
MAX([DISTINCT|ALL] <列名>)
示例:查詢選修1號課程的學生最高分數。
SELECT MAX(Grade)
FROM SC
WHER Cno= ' 1 ';
5.求最小值(對非空列)
MIN([DISTINCT|ALL] <列名>)
9) 對查詢結果分組
使用GROUP BY子句分組,用來細化集函數的作用對象
- 未對查詢結果分組,集函數將作用於整個查詢結果
- 對查詢結果分組后,集函數將分別作用於每個組
示例:求各個課程號及相應的選課人數。
SELECT Cno,COUNT(Sno)
FROM SC
GROUP BY Cno;
易犯錯誤:
SELECT Sno, Cno, COUNT(Sno)
FROM SC
GROUP BY Cno;
注意:使用GROUP BY子句后,SELECT子句的列名列表中只能出現分組屬性和集函數
用多個列分組
示例:查詢每個系男女生人數。
SELECT Sdept, Ssex, COUNT(*)
FROM Student
GROUP BY Sdept, Ssex;
使用HAVING短語篩選最終輸出結果(having都是跟隨group by對分組信息進行篩選):
示例:查詢選修了3門以上課程的學生學號。
SELECT Sno
FROM SC
GROUP BY Sno
HAVING COUNT(*) >=3;
示例:查詢有3門以上課程是90分以上的學生的學號及(90分以上的)課程數
SELECT Sno, COUNT(*)
FROM SC
WHERE Grade>=90
GROUP BY Sno
HAVING COUNT(*)>=3;
只有滿足HAVING短語指定條件的組才輸出,HAVING短語與WHERE子句的區別:作用對象不同:WHERE子句作用於基表或視圖,從中選擇滿足條件的元組;HAVING短語作用於組,從中選擇滿足條件的組。
4.2 連接查詢
前面的查詢都是針對一個表進行的。若一個查詢同時涉及兩個以上的表,則稱之為連接查詢。連接查詢是關系數據庫中最主要的查詢,包括等值連接查詢、自然連接查詢、非等值連接查詢、自身連接查詢、外連接查詢和復合條件連接查詢等。
連接查詢的WHERE字句中用來連接兩個表的條件稱為連接條件或連接謂詞,其一般格式為:
[<表名1>.] <列名1> <比較運算符> [<表名2>.] <列名2>
其中比較運算符主要有:=、>、<、>=、<=、!=(或<>)等。
此外連接謂詞還可以使用下面形式:
[<表名1>.] <列名1> between [<表名2>.] <列名2> and [<表名2>.] <列名3>
1) 等值與非等值連接查詢
當連接運算符為=時,稱為等值連接。使用其他運算符稱為非等值連接。
連接謂詞中的列名稱為連接字段。連接條件中的各連接字段類型必須是可比的,但名字不必相同。
- 等值連接
等值連接的運算符是=。
示例:查詢每個學生及其選修課程的情況。
SELECT *
FROM Student,SC
WHERE Student.Sno = SC.Sno;
查詢結果:
Student.Sno Sname Ssex Sage Sdept SC.Sno Cno Grade
95001 李勇 男 20 CS 95001 1 92
95001 李勇 男 20 CS 95001 2 85
95001 李勇 男 20 CS 95001 3 88
95002 劉晨 女 19 IS 95002 2 90
95002 劉晨 女 19 IS 95002 3 80
注:引用兩表中同名屬性時,必須加表名前綴區分。引用唯一屬性名時可以加也可以省略表名前綴。
若在等值連接中把目標列中重復的屬性列去掉則為自然連接。
- 非等值連接
不是 = 的連接操作就是非等值連接。
示例:查詢選課信息,並顯示成績級別
SELECT Sno,Cno,Grade,Stage
FROM Sc, Gstage
WHERE Grade BETWEEN Low AND High;
2) 自身連接
一個表與其自己進行連接,稱為表的自身連接。
示例:查詢每一門課的先行課名
SELECT First.Cname 課名, Second.Cname 先行課名
FROM Course First,course Second
WHERE First.Cpno = Second.Cno;
輸出:
課名 先行課名
數據庫 數據結構
信息系統 數據庫
注:需要給表起別名以示區別如示例中的First和Second;由於所有屬性名都是同名屬性,因此必須使用別名前綴,如示例中的First.Cname和Second.Cname。
3) 外連接(Outer Join)
普通連接操作只輸出滿足連接條件的元組。有時想保留不滿足條件的元組,比如說以Student表為主體列出每個學生的基本情況及其選課情況,若某個學生沒有選課,但是依舊想保留該學生的信息,這時需要使用到的就是外連接。實現方式就是以Student表為主體,對每一個學生如果沒有選課信息則選課表的屬性上填空值(Null)。
示例:查詢每個學生及其選修課程的情況(包括沒有選修課程的學生)
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student,SC
WHERE Student.Sno *= SC.Sno;
或
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student LEFT OUTER JOIN SC ON Student.Sno = SC.Sno;
查詢結果:
Student.Sno Sname Ssex Sage Sdept Cno Grade
95001 李勇 男 20 CS 1 92
95001 李勇 男 20 CS 2 85
95001 李勇 男 20 CS 3 88
95002 劉晨 女 19 IS 2 90
95002 劉晨 女 19 IS 3 80
95003 王敏 女 18 MA null null
95004 張立 男 19 IS null null
外連接類型:
- 左外連接
將左邊關系的不滿足連接條件的行輸出
WHERE 子句方式(*出現在左邊):
WHERE R.A1 *= S.A1
FROM子句方式:
FROM R LEFT [OUTER] JOIN S ON R.A1=S.A1
- 右外連接
將右邊關系的不滿足連接條件的行輸出
WHERE 子句方式(*出現在右邊) :
WHERE R.A1 =* S.A1
FROM子句方式:
FROM R RIGHT [OUTER] JOIN S ON R.A1=S.A1
- 全外連接
將兩邊關系的不滿足連接條件的行輸出
WHERE 子句方式(*出現在兩邊) :
WHERE R.A1 *=* S.A1
FROM子句方式:
FROM R FULL [OUTER] JOIN S ON R.A1=S.A1
4) 復合條件連接
上面各個連接查詢中,WHERE字句中只有一個查詢條件。WHERE字句中可以有多個連接條件,稱為復合條件連接。
示例:查詢選修2號課程且成績在90分以上的所有學生
Select Student.sno, sname
From student, sc
Where student.sno = sc.sno
And sc.cno = ‘2’
And sc.grade > 90;
4.3 嵌套查詢
1) 嵌套查詢概述
一個SELECT-FROM-WHERE語句稱為一個查詢塊。將一個查詢塊嵌套在另一個查詢塊的WHERE子句或HAVING短語的條件中的查詢稱為嵌套查詢。
示例:嵌套查詢
SELECT Sname /*外層查詢或父查詢*/
FROM Student
WHERE Sno IN
(SELECT Sno /*內層查詢/子查詢*/
FROM SC
WHERE Cno= ' 2 ');
注:子查詢中不能使用Order by。
2) 嵌套查詢分類
- 不相關子查詢:子查詢的查詢條件不依賴於父查詢
- 相關子查詢:子查詢的查詢條件依賴於父查詢
3) 引出子查詢的謂詞
- 帶有IN謂詞的子查詢
在嵌套查詢中,子查詢的結果往往是一個集合,所以謂詞IN是嵌套查詢中最經常使用的謂詞。
示例:查詢與“劉晨”在同一個系學習的學生。
此查詢要求可以分步來完成
① 確定“劉晨”所在系名
SELECT Sdept
FROM Student
WHERE Sname= ' 劉晨 ';
結果為:
Sdept
IS
② 查找所有在IS系學習的學生。
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept= ' IS ';
結果為:
Sno Sname Sdept
95001 劉晨 IS
95004 張立 IS
③ 將第一步查詢嵌入到第二步查詢的條件中
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN
(SELECT Sdept
FROM Student
WHERE Sname= ‘ 劉晨 ’);
注:本例中,子查詢的查詢條件不依賴於父查詢,所以此查詢為不相關子查詢。
本例中的查詢也可以用自身連接來完成:
SELECT S1.Sno,S1.Sname,S1.Sdept
FROM Student S1,Student S2
WHERE S1.Sdept = S2.Sdept
AND S2.Sname = '劉晨';
示例:查詢選修了課程名為“信息系統”的學生學號和姓名
SELECT Sno,Sname ③ 最后在Student關系中
FROM Student 取出Sno和Sname
WHERE Sno IN
(SELECT Sno ② 然后在SC關系中找出選
FROM SC 修了3號課程的學生學號
WHERE Cno IN
(SELECT Cno ① 首先在Course關系中找出“信
FROM Course 息系統”的課程號,結果為3號
WHERE Cname= ‘信息系統’));
或
SELECT Student.Sno,Sname
FROM Student,SC,Course
WHERE Student.Sno = SC.Sno AND
SC.Cno = Course.Cno AND
Course.Cname=‘信息系統’;
- 帶有比較運算符的子查詢
指父查詢與子查詢之間用比較運算符進行連接,當能確切知道內層查詢返回單值時,可用比較運算符(=,>,<,>=,<=,!=或< >)。
示例:假設只有一個學生劉晨,則對上例可以用 = 代替IN :
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept =
(SELECT Sdept
FROM Student
WHERE Sname= ‘劉晨’);
示例:查詢比劉晨年齡大的學生號,姓名 :
SELECT Sno,Sname
FROM Student
WHERE Sage >
(SELECT Sage
FROM Student
WHERE Sname= ‘劉晨’);
- 在HAVING中使用子查詢
示例: 查詢平均分大於95002這個學生的平均分的學號
SELECT SNO FROM SC
GROUP BY SNO
HAVING AVG(GRADE)>
(SELECT AVG(GRADE)
FROM SC
WHERE SNO=95002
)
- 帶有EXISTS謂詞的子查詢
EXISTS謂詞相當於存在量詞$。帶有EXISTS謂詞的子查詢不返回任何數據,只產生邏輯真值“TRUE”或邏輯假值“false”:
-
- 若內層查詢結果非空,則返回真值
- 若內層查詢結果為空,則返回假值
由EXISTS引出的子查詢,其目標列表達式通常都用* ,因為帶EXISTS的子查詢只返回真值或假值,給出列名無實際意義。由EXISTS引出的子查詢一般都是相關子查詢。所有其他謂詞的子查詢都能用帶EXISTS謂詞的子查詢等價替換;一些帶EXISTS或NOT EXISTS謂詞的子查詢不能被其他形式的子查詢等價替換。
示例:查詢所有選修了1號課程的學生姓名
- 用IN子查詢實現:
SELECT Sname
FROM Student
WHERE Sno IN (Select Sno
FROM sc
WHERE Cno= ‘1’);
- 用連接運算實現:
SELECT distinct Sname
FROM Student, SC
WHERE Student.Sno=SC.Sno
AND SC.Cno= '1';
- 用EXISTS語句實現:
SELECT Sname FROM Student
WHERE EXISTS
(SELECT *
FROM SC /*相關子查詢*/
WHERE Sno=Student.Sno AND Cno= '1');
4.4 集合查詢
Select語句的查詢結果是元組的集合,所以多個select語句的結果可進行集合操作。集合操作主要包括並操作(union)、交操作(intersect)和差操作(except)。注意:參加集合操作的各查詢結果的列數必須相同;對應項的數據類型也必須相同。
1) 並操作
形式
<查詢塊>
UNION
<查詢塊>
示例:查詢計算機科學系的學生與年齡不大於19歲的學生的並集。
方法一:並操作會自動去除相同記錄,而union all則不會
SELECT *
FROM Student
WHERE Sdept= 'CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;
方法二:
SELECT DISTINCT *
FROM Student
WHERE Sdept= 'CS' OR Sage<=19;
2) 交操作
示例:查詢計算機科學系的學生與年齡不大於19歲的學生的交集
SELECT *
FROM Student
WHERE Sdept='CS'
INTERSECT
SELECT *
FROM Student
WHERE Sage<=19
實際上就是查詢計算機科學系中年齡不大於19歲的學生:
SELECT *
FROM Student
WHERE Sdept= 'CS' AND Sage<=19;
3) 差操作
示例1:查詢計算機科學系的學生與年齡不大於19歲的學生的差集。
SELECT *
FROM Student
WHERE Sdept='CS'
MINUS
SELECT *
FROM Student
WHERE Sage <=19;
實際上是查詢計算機科學系中年齡大於19歲的學生:
SELECT *
FROM Student
WHERE Sdept= 'CS' AND Sage>19;
示例2:查詢未選課的學號(所有學號與選過課的學號的差集)
SELECT Sno
FROM Student
EXCEPT
SELECT Sno
FROM SC;
NOT IN實現:
SELECT Sno
FROM Student
WHERE Sno NOT IN
(SELECT Sno
FROM SC);
NOT EXISTS實現:
SELECT Sno
FROM Student S
WHERE NOT EXISTS
(SELECT *
FROM SC WHERE SC.SNO=S.SNO);
實際應用中交操作和差操作應用較少,並操作使用較多。
4.5 SELECT語句的一般格式
SELECT [ALL|DISTINCT] <目標列表達式> [別名] [ ,<目標列表達式> [別名]] …
FROM <表名或視圖名> [別名] [,<表名或視圖名> [別名]] …
[WHERE <條件表達式>]
[GROUP BY <列名1>[,<列名1’>] ...[HAVING <條件表達式>] ]
[ORDER BY <列名2> [ASC|DESC] [,<列名2’> [ASC|DESC] ] … ];
5 數據更新
數據更新操作有3種:向表中添加若干行數據、修改表中的數據和刪除表中的若干行數據。在SQL中有相應的三類語句。
5.1 插入數據
SQL的數據插入語句INSERT通常有兩種形式。一種是插入一個元組,另一種是插入子查詢結果。后者可以一次插入多個元組。
1) 插入單個元組
語句格式:
INSERT
INTO <表名> [(<屬性列1>[,<屬性列2 >…)]
VALUES (<常量1> [,<常量2>] …)
其功能是將新元組插入指定表中。其中新元組的屬性列1的值為常量1,屬性列2的值為常量2,…。INTO子句中沒有出現的屬性列,新元組在這些列上將取空值。但必須注意的是,在表定義時說明了not null的屬性列不能取空值,否則會出錯。
示例:插入一條選課記錄( '95020','1 '),新插入的記錄在Grade列上取空值
INSERT
INTO SC(Sno,Cno)
VALUES (' 95020 ',' 1 ');
示例:將一個新學生記錄(學號:95020;姓名:陳冬;性別:男;所在系:IS;年齡:18歲)插入到Student表中。
INSERT
INTO Student(sno,sname,ssex,sdept,sage)
VALUES ('95020','陳冬','男','IS',18);
或
INSERT INTO Student VALUES ('95020','陳冬','男','IS',18);
注:當新元組在所有屬性列上都指定了值,並且順序一致,則可以省略屬性名
INTO子句:
- 指定要插入數據的表名及屬性列
- 屬性列的順序可與表定義中的順序不一致
- 沒有指定屬性列:表示要插入的是一條完整的元組,且屬性列屬性與表定義中的順序一致
- 指定部分屬性列:插入的元組在其余屬性列上取空值
VALUES子句 :
- 提供的值必須在值的個數和值的類型與INTO子句匹配
2) 插入子查詢結果
子查詢不僅可以嵌套在select語句中,用以構造父查詢的條件,也可以嵌套在insert語句中,用以生成要插入的批量數據。
語句格式:
INSERT
INTO <表名> [(<屬性列1> [,<屬性列2>… )]
子查詢;
示例:對每一個系,求學生的平均年齡,並把結果存入數據庫。
第一步:建表
CREATE TABLE Deptage
(Sdept CHAR(15) /* 系名*/
Avgage INT); /*學生平均年齡*/
第二步:插入數據
INSERT
INTO Deptage(Sdept,Avgage)
SELECT Sdept,AVG(Sage)
FROM Student
GROUP BY Sdept;
5.2 修改數據
修改操作又稱為更新操作,其一般語句格式:
UPDATE <表名>
SET <列名>=<表達式>[,<列名>=<表達式>]…
[WHERE <條件>];
其功能是修改指定表中滿足WHERE子句條件的元組。其中set子句給出<表達式>[的值用於取代相應的屬性值。如果省略WHERE子句,則表示要修改表中的所有元組。
修改指定表中滿足WHERE子句條件的元組。
1) 修改某一個元組的值
示例:將學生95001的年齡改為22歲。
UPDATE Student
SET Sage=22
WHERE Sno=' 95001 ';
2) 修改多個元組的值
示例1:將所有學生的年齡增加1歲。
UPDATE Student
SET Sage= Sage+1;
示例2:將信息系所有學生的年齡增加1歲。
UPDATE Student
SET Sage= Sage+1
WHERE Sdept=' IS ';
3) 帶子查詢的修改語句
示例:將計算機科學系全體學生的成績置零。
UPDATE SC
SET Grade=0
WHERE SNO IN
(SELETE SNO
FROM Student
WHERE SDEPT=‘CS’);
5.3 刪除數據
刪除語句的一般格式為:
DELETE
FROM <表名>
[WHERE <條件>];
DELETE語句的功能是刪除指定表中滿足WHERE子句條件的所有元組。如果省略WHERE子句表示要刪除表中所有元組,但是表的定義仍在字典中。
1) 刪除某一個元組的值
示例:刪除學號為95019的學生記錄。
DELETE
FROM Student
WHERE Sno='95019';
2) 刪除多個元組的值
示例:刪除2號課程的所有選課記錄。
DELETE
FROM SC;
WHERE Cno='2';
示例:刪除所有的學生選課記錄。
DELETE
FROM SC;
3) 帶子查詢的刪除語句
示例:刪除計算機科學系所有學生的選課記錄。
DELETE
FROM SC
WHERE SNO IN
(SELETE SNO
FROM Student
WHERE SDEPT='CS');
6 視圖
視圖是從一個或幾個基本表(或視圖)導出的表。它與基本表不同,是一個虛表。數據庫中只存放視圖的定義,而不存放視圖對應的數據,這些數據仍存放在原來的基本表中,不會出現數據冗余。所以基表中的數據發生變化,從視圖中查詢出的數據也隨之改變。
視圖一經定義,就可以和基本表一樣被查詢、被刪除。也可以在一個視圖之上再定義新的視圖,但對視圖的更新(增、刪、改)操作則有一定的限制。
6.1 定義視圖
語句格式:
CREATE VIEW <視圖名> [(<列名> [,<列名>]…)]
AS <子查詢>
[WITH CHECK OPTION];
其中,子查詢可以是任意復雜的select語句,但通常不允許含有order by子句和distinct短語。WITH CHECK OPTION表示對視圖進行update,insert和delete操作時要保證更新、插入或刪除的行滿足視圖定義中的謂詞條件(即子查詢中的條件表達式)。
1) 建立視圖
示例1:建立信息系學生的視圖。
CREATE VIEW IS_Student(No,Name,Age) AS
SELECT Sno, Sname, Sage
FROM Student
WHERE Sdept= 'IS'
WITH CHECK OPTION;
注:由於在定義視圖時加上了WITH CHECK OPTION子句,以后對該視圖進行增刪改操作時,RDBMS會自動加上Sdept=‘IS’的條件。
示例2: 建立1號課程的選課視圖,並要求透過該視圖進行的更新操作只涉及1號課程,同時對該視圖的任何操作只能在工作時間進行。
CREATE VIEW IS_SC AS
SELECT Sno,Cno,Grade
FROM SC
WHERE Cno= '1'
AND TO_CHAR(SYSDATE,'HH24') BETWEEN 9 AND 17
AND TO_CHAR(SYSDATE,'D') BETWEEN 2 AND 6
WITH CHECK OPTION;
視圖不僅可以建立在單個基本表上,也可以建立在多個基本表上;不僅可以建立在一個或多個基本表上,也可以建立在一個或多個已定義好的視圖上;或者建立在基本表與視圖上。
示例3:建立新型系統選修了1號課程的學生的視圖
CREATE VIEW IS_SI(Sno,Sname,Sgrade) AS
SELECT Student.Sno, Sname, Grade
FROM Student,SC
WHERE Sdept= 'IS'
AND Student.Sno = SC.Sno
AND SC.Cno = ‘1’;
視圖的定義也可以包含分組計算的值,如下例。
示例4:實現查詢每個同學的平均成績
CREAT VIEW S_G(Sno ,Gavg)
AS
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno;
2) 刪除視圖
格式:
DROP VIEW <視圖名> [CASCADE];
視圖刪除后視圖的定義將從數據字典中刪除。如果該視圖上還導出了其他視圖,則使用CASCADE級聯刪除語句,把該視圖和由它導出的所有視圖一起刪除。
基本表刪除后,由該基本表導出的所有視圖沒有刪除,但均已無法使用了。
示例:刪除視圖IS_SI
DROP VIEW IS_SI;
6.2 查詢視圖
示例:視圖建立后, 可對視圖查詢, 如同基本表:
SELECT Name
FROM IS_Student
DBMS執行CREATE VIEW語句時只是把視圖的定義存入數據字典,並不執行其中的SELECT語句。在對視圖查詢時,按視圖的定義從基本表中將數據查出。
6.3 更新視圖
更新視圖是指通過視圖來插入、刪除和修改數據。由於視是不實際存儲數據的虛表,因此對視圖的操作,最終要轉換為對基本表的操作。
為了防止用戶通過視圖對數據進行增刪改時,有意無意地對不屬於視圖范圍內的基本表數據進行操作,可在定義視圖時加上WITH CHECK OPTION子句。這樣在視圖上增刪改數據時,RDBMS會檢查視圖定義中的條件,若不滿足條件,則拒絕執行該操作。
示例:將信息系學生視圖IS_Student中學號為200215122的學生姓名改為“劉晨”。
UPDATE IS_Student
SET Sname = ‘劉晨’
WHERE Sno = ‘200215122’;
轉換后的更新語句為:
UPDATE Student
SET Sname = ‘劉晨’
WHERE Sno = ‘200215122’ AND Sdept = ‘IS’;
注:如果IS_Student視圖定義的時候含有WITH CHECK OPTION子句,則對視圖IS_Student的更新范圍只能是信息系學生信息。
在關系數據庫中,並不是所有的視圖都是可以更新的,因為有些視圖的更新不能唯一地有意義地轉換成對相應基本表的更新。例如,建立視圖中定義的S_G視圖,如果想把視圖S_G中學號為200215121的學生的平均成績改成90分,SQL語句如下:
UPDATE S_G
SET Gavg = 90
WHERE Sno = ‘200215121’;
注:對這個視圖的更新是無法轉換成對基本表SC的更新的,因為系統無法修改各科成績,以使平均成績為90。所以S_G視圖是不可更新的。
目前各個關系數據庫系統一般都只允許對行列子集視圖進行更新,而且各個系統對視圖的更新還有更進一步的規定,由於各系統實現方法上的差異,這些規定也不盡相同。
例如DB2規定:
1) 若視圖是由兩個以上基本表導出的,則此視圖不允許更新。
2) 若視圖的字段來自字段表達式或常數,則不允許對此視圖執行INSERT和UPDATE操作,但允許執行delete操作。
3) 若視圖的字段來自聚集函數,則此視圖不允許更新
4) 若視圖定義中含有Group By子句,則此視圖不允許更新
5) 若視圖定義中含有DISTINGCT短語,則此視圖不允許更新
6) 若視圖定義中有嵌套查詢,並且內層查詢的from子句中設計的表也是導出該視圖的基本表,則此視圖不允許更新。例如,將SC中成績在平均成績之上的元組定義成一個視圖GOOD_SC:
CREATE VIEW GOOD_SC
AS
SELECT Sno,Cno,Grade
FROM SC
WHERE Grade > ( SELECT AVG(Grade)FROM SC );
導出視圖GOOD_SC的基本表是SC,內層查詢中涉及的表也是SC,所以視圖GOOD_SC是不允許更新的
7) 一個不允許更新的視圖也是不允許更新。
6.4 視圖的作用
視圖最終是定義在基本表之上的,對視圖的一切操作最終也要轉換為對基本表的操作。而且對於非行列子集視圖進行更新時還有可能出現問題。既然如此,為什么還要定義視圖呢?這是因為合理使用視圖能夠帶來許多好處。
1) 簡化用戶的操作
視圖機制是用戶可以將注意力集中在所關心的數據上,是數據庫看起來結構清晰、簡單。並且可以簡化用戶的數據查詢操作。例如,那些定義了若干張表連接的視圖,就將表與表之間的連接操作對用戶隱蔽起來了。換句話說,用戶所做的只是對一個虛表的簡單查詢,而這個虛表是怎樣得來的,用戶無需了解。
2) 使用戶能以多種角度看待同一數據
視圖機制能使不同用戶以不同方式看待同一數據,當許多不同種類的用戶共享同一個數據庫時,這種靈活性非常重要。
3) 提供了一定程度的邏輯獨立性
數據的物理獨立性是指用戶的應用程序不依賴於數據的物理結構;數據的邏輯獨立性是指當數據庫重構造時,如增加新的關系或對原有關系增加新的字段等,用戶的應用程序不會受影響。
例:數據庫邏輯結構發生改變學生關系Student(Sno, Sname, Ssex,Sage,Sdept) “垂直”地分成兩個基本表:
SX(Sno,Sname,Sage)
SY(Sno,Ssex,Sdept)
通過建立一個視圖Student:
CREATE VIEW Student(Sno,Sname,Ssex,Sage,Sdept)
AS
SELECT SX.Sno,SX.Sname,SY.Ssex,SX.Sage,SY.Sdept
FROM SX,SY
WHERE SX.Sno=SY.Sno;
使用戶的外模式保持不變,從而對原Student表的查詢程序不必修改。
4) 能夠對機密數據提供安全保護
對不同用戶定義不同視圖,使每個用戶只能看到他有權看到的數據;通過WITH CHECK OPTION對關鍵數據定義操作限制,限制操作的范圍和時間等。