筆記中所有的練習(xí)均使用MYSQL數(shù)據(jù)庫(kù)
數(shù)據(jù)表的創(chuàng)建和管理
- 創(chuàng)建數(shù)據(jù)表
CREATE TABLE person
(
name varchar(20),
age int
);
- 定義非空約束
CREATE TABLE person
(
name varchar(20) NOT NULL,
age int NOT NULL
);
- 定義默認(rèn)值
為字段設(shè)置一個(gè)默認(rèn)值诱桂,當(dāng)沒(méi)有為該字段賦值的時(shí)候使用該默認(rèn)值。
CREATE TABLE teacher
(
number varchar(20),
name varchar(20),
age int,
master varchar(5) DEFAULT 'NO'
);
- 定義主鍵
通過(guò)主鍵可以唯一定位一條數(shù)據(jù)記錄浪册,并且在進(jìn)行外鍵關(guān)聯(lián)的時(shí)候也需要被關(guān)聯(lián)的數(shù)據(jù)表具有主鍵。在創(chuàng)建表的時(shí)候定義主鍵是通過(guò)PRIMARY KEY關(guān)鍵字來(lái)進(jìn)行定義的佛寿。在DB2中壶熏,主鍵字段必須是非空字段(添加非空約束),否則會(huì)報(bào)錯(cuò)咸包。
CREATE TABLE bus
(
number varchar(20),
name varchar(20),
usedAge int,
PRIMARY KEY (number)
);
聯(lián)合主鍵是指將多個(gè)字段聯(lián)合起來(lái)作為主鍵桃序。
CREATE TABLE bus
(
number varchar(20),
name varchar(20),
usedAge int,
PRIMARY KEY (number,name)
);
- 定義外鍵
通過(guò)外鍵可以把互相獨(dú)立的表關(guān)聯(lián)起來(lái)。
定義格式為:
FOREIGN KEY 外鍵字段名稱 REFERENCES 目標(biāo)表名(被關(guān)聯(lián)的字段)
我們首先建一張部門信息表:
CREATE TABLE department
(
id varchar(20),
name varchar(20),
level int,
PRIMARY KEY (id)
);
創(chuàng)建員工信息表,將員工信息同部門信息表之間創(chuàng)建關(guān)聯(lián)關(guān)系烂瘫,員工信息表中的部門id作為外鍵之間部門信息表中的主鍵id媒熊。
CREATE TABLE employee
(
number varchar(20),
name varchar(20),
departmentId varchar(20),
FOREIGN KEY (departmentId) REFERENCES department(id)
);
- 修改數(shù)據(jù)表
使用語(yǔ)法是:
ALTER TABLE 待修改的表名 ADD 字段名 字段類型
ALTER TABLE 待修改的表名 DROP 字段 - 刪除數(shù)據(jù)表
DROP TABLE 表名
數(shù)據(jù)的增刪改
首先創(chuàng)建兩張表T_Person、T_Debt
CREATE TABLE T_Person(
FName VARCHAR(20),
FAge INT,
FRemark VARCHAR(20),
PRIMARY KEY(FName)
);
CREATE TABLE T_Debt(
FNumber VARCHAR(20),
FAmount DECIMAL(10,2) NOT NULL,
FPerson VARCHAR(20),
PRIMARY KEY(FNumber),
FOREIGN KEY(FPerson) REFERENCES T_Person(FName)
);
1.簡(jiǎn)單的插入語(yǔ)句
INSERT INTO 表名(字段名) VALUES(字段值)
例如向表T_Person中插入數(shù)據(jù)
INSERT INTO T_Person(FName,FAge,FRemark) VALUES('Jim',20,'USA');
INSERT INTO T_Person(FName,FAge,FRemark) VALUES('Lili',22,'China');
INSERT INTO T_Person(FName,FAge,FRemark) VALUES('XiaoWang',17,'China');
查看表格T_Person
select * from T_Person;
+----------+------+---------+
| FName | FAge | FRemark |
+----------+------+---------+
| Jim | 20 | USA |
| Lili | 22 | China |
| XiaoWang | 17 | China |
+----------+------+---------+
也可以使用另一種方式坟比,不指定插入的表列芦鳍,那么這種情況下就會(huì)按照定義表中字段的順序來(lái)進(jìn)行插入。
例如:
INSERT INTO T_Person VALUES('luren1',23,'China');
select * from T_Person;
+----------+------+---------+
| FName | FAge | FRemark |
+----------+------+---------+
| Jim | 20 | USA |
| Lili | 22 | China |
| luren1 | 23 | China |
| XiaoWang | 17 | China |
+----------+------+---------+
- 非空約束對(duì)數(shù)據(jù)插入的影響
如果一個(gè)字段添加了非空約束葛账,那么就不能想這個(gè)字段中插入NULL值柠衅。
例如T_Debt中的FAmount字段為非空字段,如果我們執(zhí)行如下的插入操作
INSERT INTO T_Debt(FNumber,FPerson) VALUES('1','Jim');
就會(huì)報(bào)錯(cuò)
ERROR 1364 (HY000): Field 'FAmount' doesn't have a default value
- 主鍵對(duì)數(shù)據(jù)插入的影響
主鍵值在同一張表中必須是唯一的籍琳,如果插入了表中已經(jīng)存在的主鍵值就會(huì)違反主鍵約束而報(bào)異常菲宴。
例如:
INSERT INTO T_Debt(FNumber,FAmount,FPerson) VALUES('1',300,'Jim');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
- 外鍵對(duì)數(shù)據(jù)插入的影響
外鍵是指向另一個(gè)表中已有數(shù)據(jù)的約束,因此外鍵值必須在目標(biāo)表中尋在趋急,如果插入的數(shù)據(jù)在目標(biāo)表中不存在的話就會(huì)導(dǎo)致違反外鍵約束異常喝峦。
例如T_Debt表中的字段FPerson字段是指向表T_Person中的FName字段的外鍵,如果我們執(zhí)行下面的SQL:
INSERT INTO T_Debt(FNumber,FAmount,FPerson) VALUES('3',100,'Jerry');
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`t_debt`, CONSTRAINT `t_debt_ibfk_1` FOREIGN KEY (`FPerson`) REFERENCES `T_Person` (`FName`));
因?yàn)門_Person中不存在Jerry呜达。
- 數(shù)據(jù)的更新
UPDATE語(yǔ)句
例如將數(shù)據(jù)表T_Person中所有人員的FREMARK字段更新為‘SuperMan’谣蠢。
UPDATE T_Person SET FRemark = 'SuperMan';
select * from T_Person;
+----------+------+----------+
| FName | FAge | FRemark |
+----------+------+----------+
| Jim | 20 | SuperMan |
| Lili | 22 | SuperMan |
| luren1 | 23 | SuperMan |
| XiaoWang | 17 | SuperMan |
+----------+------+----------+
- 帶WHERE子句的UPDATE語(yǔ)句
只更新符合過(guò)濾條件的行
例如
UPDATE T_Person SET FAge = 12 WHERE FName = 'Jim';
select * from T_Person;
+----------+------+----------+
| FName | FAge | FRemark |
+----------+------+----------+
| Jim | 12 | SuperMan |
| Lili | 22 | SuperMan |
| luren1 | 23 | SuperMan |
| XiaoWang | 17 | SuperMan |
+----------+------+----------+
- 主鍵對(duì)數(shù)據(jù)更新的影響
如果更新的時(shí)候指定的主鍵和表中已經(jīng)存在的主鍵重復(fù)的話,就會(huì)導(dǎo)致違反主鍵約束異常闻丑。
select * from T_Debt;
+---------+---------+---------+
| FNumber | FAmount | FPerson |
+---------+---------+---------+
| 1 | 200.00 | Jim |
| 2 | 300.00 | Jim |
| 3 | 100.00 | Lili |
+---------+---------+---------+
UPDATE T_Debt SET FNumber = '1' WHERE FPerson = 'Lili';
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
- 外鍵對(duì)數(shù)據(jù)更新的影響
外鍵值必須在目標(biāo)表中存在漩怎,如果更新后的外鍵值在目標(biāo)表中不存在的話就會(huì)導(dǎo)致違反外鍵約束異常。
select * from T_Debt;
+---------+---------+---------+
| FNumber | FAmount | FPerson |
+---------+---------+---------+
| 1 | 200.00 | Jim |
| 2 | 300.00 | Jim |
| 3 | 100.00 | Lili |
+---------+---------+---------+
select * from T_Person;
+----------+------+----------+
| FName | FAge | FRemark |
+----------+------+----------+
| Jim | 12 | SuperMan |
| Lili | 22 | SuperMan |
| luren1 | 23 | SuperMan |
| XiaoWang | 17 | SuperMan |
+----------+------+----------+
UPDATE T_Debt set FPerson = 'Merry' WHERE FNumber = '1';
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`t_debt`, CONSTRAINT `t_debt_ibfk_1` FOREIGN KEY (`FPerson`) REFERENCES `T_Person` (`FName`))
UPDATE T_Debt set FPerson = 'luren1' WHERE FNumber = '1';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
select * from T_Debt;
+---------+---------+---------+
| FNumber | FAmount | FPerson |
+---------+---------+---------+
| 1 | 200.00 | luren1 |
| 2 | 300.00 | Jim |
| 3 | 100.00 | Lili |
+---------+---------+---------+
- 數(shù)據(jù)的刪除
例如:
DELETE FROM T_Person;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t_debt`, CONSTRAINT `t_debt_ibfk_1` FOREIGN KEY (`FPerson`) REFERENCES `T_Person` (`FName`))
因?yàn)門_Debt中的FPerson是指向T_Person的外鍵嗦嗡,所以必須先刪除T_Debt才能刪除T_Person
DELETE和Drop的區(qū)別
DELETE僅刪除數(shù)據(jù)庫(kù)中的記錄不會(huì)刪除數(shù)據(jù)表勋锤,而DROP不僅會(huì)刪除記錄而且會(huì)刪除表。
delete from T_Debt where FNumber = '1';
select * from T_Debt;
+---------+---------+---------+
| FNumber | FAmount | FPerson |
+---------+---------+---------+
| 2 | 300.00 | Jim |
| 3 | 100.00 | Lili |
+---------+---------+---------+
delete from T_Debt;
select * from T_Debt;
Empty set (0.00 sec)
drop table T_Debt;
Query OK, 0 rows affected (0.01 sec)
select * from T_Debt;
ERROR 1146 (42S02): Table 'test.t_debt' doesn't exist
數(shù)據(jù)的檢索
首先創(chuàng)建表T_Employee
CREATE TABLE T_Employee
(
FNumber VARCHAR(20),
FName VARCHAR(20),
FAge INT,
FSalary DECIMAL(10,2),
PRIMARY KEY(FNumber)
);
INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('DEV001','Tom',25,8300);
INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('DEV002','Jerry',28,2300.80);
INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('SALES001','John',23,5000);
INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('SALES002','Kerry',28,6200);
INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('SALES003','Stone',22,1200);
INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('HR001','Jane',23,2200.88);
INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('HR002','Tina',25,5200.36);
INSERT INTO T_Employee(FNumber,FName,FAge,FSalary) VALUES('IT001','Smith',28,3900);
- 檢索出所有的列
select * from T_Employee;
+----------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+----------+-------+------+---------+
| DEV001 | Tom | 25 | 8300.00 |
| DEV002 | Jerry | 28 | 2300.80 |
| HR001 | Jane | 23 | 2200.88 |
| HR002 | Tina | 25 | 5200.36 |
| IT001 | Smith | 28 | 3900.00 |
| SALES001 | John | 23 | 5000.00 |
| SALES002 | Kerry | 28 | 6200.00 |
| SALES003 | Stone | 22 | 1200.00 |
+----------+-------+------+---------+
- 檢索出需要的列
select FNumber,FName from T_Employee;
+----------+-------+
| FNumber | FName |
+----------+-------+
| DEV001 | Tom |
| DEV002 | Jerry |
| HR001 | Jane |
| HR002 | Tina |
| IT001 | Smith |
| SALES001 | John |
| SALES002 | Kerry |
| SALES003 | Stone |
+----------+-------+
- 列的別名
定義別名的語(yǔ)法格式:
列名 AS 別名
AS也可以省略
例如:
select FNumber AS Number,FName AS Name,FAge AS Age,FSalary AS Salary
FROM T_Employee;
+----------+-------+------+---------+
| Number | Name | Age | Salary |
+----------+-------+------+---------+
| DEV001 | Tom | 25 | 8300.00 |
| DEV002 | Jerry | 28 | 2300.80 |
| HR001 | Jane | 23 | 2200.88 |
| HR002 | Tina | 25 | 5200.36 |
| IT001 | Smith | 28 | 3900.00 |
| SALES001 | John | 23 | 5000.00 |
| SALES002 | Kerry | 28 | 6200.00 |
| SALES003 | Stone | 22 | 1200.00 |
+----------+-------+------+---------+
- 按條件過(guò)濾檢索
例如:
檢索出工資小于5000的員工
select * from T_Employee where FSalary < 5000;
+----------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+----------+-------+------+---------+
| DEV002 | Jerry | 28 | 2300.80 |
| HR001 | Jane | 23 | 2200.88 |
| IT001 | Smith | 28 | 3900.00 |
| SALES003 | Stone | 22 | 1200.00 |
+----------+-------+------+---------+
- 數(shù)據(jù)匯總
sql中提供了一些聚合函數(shù)來(lái)完成計(jì)算條數(shù)侥祭、找出最大值或最小值叁执、計(jì)算平均值等
函數(shù)名 說(shuō)明
MAX 計(jì)算字段最大值
MIN 計(jì)算字段最小值
AVG 計(jì)算字段平均值
SUM 計(jì)算字段和
COUNT 統(tǒng)計(jì)數(shù)據(jù)條數(shù)
例如
查找大于25歲員工的最高工資
select MAX(FSalary) from T_Employee where FAge > 25;
+--------------+
| MAX(FSalary) |
+--------------+
| 6200.00 |
+--------------+
計(jì)算工資大于3800的員工的平均年齡
select AVG(FAge) from T_Employee where FSalary > 3800;
+-----------+
| AVG(FAge) |
+-----------+
| 25.8000 |
+-----------+
計(jì)算公司每個(gè)月應(yīng)該支出工資總額
select SUM(FSalary) from T_Employee;
+--------------+
| SUM(FSalary) |
+--------------+
| 34302.04 |
記錄條數(shù)COUNT
select COUNT(*) from T_Employee;
+----------+
| COUNT(*) |
+----------+
| 8 |
+----------+
INSERT INTO T_Employee(FNumber,FAge,FSalary) VALUES('IT002',27,2800);
Query OK, 1 row affected (0.00 sec)
select * from T_Employee;
+----------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+----------+-------+------+---------+
| DEV001 | Tom | 25 | 8300.00 |
| DEV002 | Jerry | 28 | 2300.80 |
| HR001 | Jane | 23 | 2200.88 |
| HR002 | Tina | 25 | 5200.36 |
| IT001 | Smith | 28 | 3900.00 |
| IT002 | NULL | 27 | 2800.00 |
| SALES001 | John | 23 | 5000.00 |
| SALES002 | Kerry | 28 | 6200.00 |
| SALES003 | Stone | 22 | 1200.00 |
+----------+-------+------+---------+
select count(*),count(FNumber),count(FName) from T_Employee;
+----------+----------------+--------------+
| count(*) | count(FNumber) | count(FName) |
+----------+----------------+--------------+
| 9 | 9 | 8 |
+----------+----------------+--------------+
可以看到FName的統(tǒng)計(jì)數(shù)據(jù)為8,是因?yàn)镕Name中有一個(gè)NULL值矮冬。
- 排序
select語(yǔ)句允許使用order by子句來(lái)對(duì)結(jié)果集進(jìn)行排序谈宛,它允許指定按照一個(gè)或多個(gè)列進(jìn)行排序,也可以指定排列方式是升序還是降序胎署。
select * from T_Employee order by FAge ASC;
+----------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+----------+-------+------+---------+
| SALES003 | Stone | 22 | 1200.00 |
| HR001 | Jane | 23 | 2200.88 |
| SALES001 | John | 23 | 5000.00 |
| DEV001 | Tom | 25 | 8300.00 |
| HR002 | Tina | 25 | 5200.36 |
| DEV002 | Jerry | 28 | 2300.80 |
| IT001 | Smith | 28 | 3900.00 |
| SALES002 | Kerry | 28 | 6200.00 |
+----------+-------+------+---------+
使用多個(gè)排序規(guī)則吆录,如果第一個(gè)排序規(guī)則沒(méi)有辦法區(qū)分兩條記錄的順序,則會(huì)按照第二個(gè)排序規(guī)則進(jìn)行排序琼牧,以此類推恢筝。
- 高級(jí)數(shù)據(jù)過(guò)濾
- 通配符過(guò)濾
單字符匹配
進(jìn)行單字符匹配的通配符是半角下劃線“_”哀卫,它匹配單個(gè)出現(xiàn)的字符。例如通配符表達(dá)式“b_d”匹配第一個(gè)字符為b撬槽,第二個(gè)字符為任意字符此改,第三個(gè)字符為d的字符串。
例如:
select * from T_Employee where FName like '_erry';
+----------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+----------+-------+------+---------+
| DEV002 | Jerry | 28 | 2300.80 |
| SALES002 | Kerry | 28 | 6200.00 |
+----------+-------+------+---------+
多字符匹配
多字符匹配的通配符為半角百分號(hào)“%”侄柔,它匹配任意次數(shù)(零或多個(gè))出現(xiàn)的任意字符共啃。例如通配符表達(dá)式“k%”匹配以“k”開(kāi)頭、任意長(zhǎng)度的字符串暂题。
例如:
檢索FName字段中以“T”開(kāi)頭移剪,長(zhǎng)度任意的值,“T%”
select * from T_Employee where FName like 'T%';
+---------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+---------+-------+------+---------+
| DEV001 | Tom | 25 | 8300.00 |
| HR002 | Tina | 25 | 5200.36 |
+---------+-------+------+---------+
單字符匹配和多字符匹配一起使用
檢索T_Employee表中的FName字段匹配如下規(guī)則的數(shù)據(jù)行:最后一個(gè)字符為任意字符敢靡,倒數(shù)第二個(gè)字符為“n”挂滓,長(zhǎng)度任意的字符串⌒ル剩“%n_”
例如
select * from T_Employee where FName like '%n_';
+----------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+----------+-------+------+---------+
| HR001 | Jane | 23 | 2200.88 |
| HR002 | Tina | 25 | 5200.36 |
| SALES003 | Stone | 22 | 1200.00 |
+----------+-------+------+---------+
集合匹配
進(jìn)行集合匹配的時(shí)候使用通配符“[]”,方括號(hào)包含一個(gè)字符集赶站,它匹配與字符集中任意一個(gè)字符相匹配的字符。例如通配符表達(dá)式“[bt]%”匹配第一個(gè)字符為b或者t纺念,長(zhǎng)度任意的字符串贝椿。但是mysql數(shù)據(jù)庫(kù)中不支持這種方式。
例如檢索T_Employee中FName字段中以“S”或者“J”開(kāi)頭的長(zhǎng)度任意的數(shù)據(jù)記錄陷谱。
select * from T_Employee where FName like '[SJ]%';
使用來(lái)對(duì)集合取反烙博,例如通配符表達(dá)式“[bt]%”匹配第一個(gè)字符不為b或者t的長(zhǎng)度不限的字符串。
select * from T_Employee where FName like '[SJ]%';
不過(guò)雖然通配符過(guò)濾功能很強(qiáng)大烟逊,但是通配符過(guò)濾進(jìn)行檢索的時(shí)候渣窜,數(shù)據(jù)庫(kù)系統(tǒng)會(huì)對(duì)全表進(jìn)行掃描,所以執(zhí)行速度會(huì)非常慢宪躯。因此在使用其他方式可以實(shí)現(xiàn)相同效果的情況下盡量不要使用通配符過(guò)濾乔宿。
- 空值檢測(cè)
如果要檢測(cè)T_Employee中所有姓名未知的員工的信息,不能使用FName=null访雪,而是要使用關(guān)鍵字IS NULL详瑞。使用方法如下“待檢測(cè)字段名IS NULL”。
例如:
select * from T_Employee where FName IS NULL;
+---------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+---------+-------+------+---------+
| IT002 | NULL | 27 | 2800.00 |
+---------+-------+------+---------+
如果要檢測(cè)非空字段需要使用IS NOT NULL臣缀。
例如:
select * from T_Employee where FName IS NOT NULL;
+----------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+----------+-------+------+---------+
| DEV001 | Tom | 25 | 8300.00 |
| DEV002 | Jerry | 28 | 2300.80 |
| HR001 | Jane | 23 | 2200.88 |
| HR002 | Tina | 25 | 5200.36 |
| IT001 | Smith | 28 | 3900.00 |
| SALES001 | John | 23 | 5000.00 |
| SALES002 | Kerry | 28 | 6200.00 |
| SALES003 | Stone | 22 | 1200.00 |
+----------+-------+------+---------+
- 反義運(yùn)算符
在MYSQL中不等于使用"<>"運(yùn)算符坝橡,不大于就是小于等于,不小于就是大于等于精置。
也可以使用NOT運(yùn)算符將一個(gè)表達(dá)式的值取反计寇。也就是將為“真”的表達(dá)式的結(jié)果變?yōu)椤凹佟薄J褂梅绞绞恰癗OT(表達(dá)式)”。
例如檢索出所有年齡不等于22并且工資不小于2000元的員工番宁。
select * from T_Employee where not(FAge=22) and not(FSalary<2000);
+----------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+----------+-------+------+---------+
| DEV001 | Tom | 25 | 8300.00 |
| DEV002 | Jerry | 28 | 2300.80 |
| HR001 | Jane | 23 | 2200.88 |
| HR002 | Tina | 25 | 5200.36 |
| IT001 | Smith | 28 | 3900.00 |
| IT002 | NULL | 27 | 2800.00 |
| SALES001 | John | 23 | 5000.00 |
| SALES002 | Kerry | 28 | 6200.00 |
+----------+-------+------+---------+
推薦除了不等于“<>”之外蹲堂,其他的使用NOT運(yùn)算符的方式。
- 多值檢測(cè)
例如檢索出公司年齡為23贝淤、25、28的員工的信息政供。
我們可以使用or來(lái)連接多個(gè)判斷播聪,但是如果要檢索的年齡值有很多個(gè),我們就要連接多個(gè)or布隔,這樣寫(xiě)起來(lái)就會(huì)很麻煩离陶,并且容易出錯(cuò)、維護(hù)難度也大衅檀,所以可以使用SQL中的IN語(yǔ)句招刨。使用方法是“IN(值1,值2哀军,值3.......)”沉眶。
例如
select * from T_Employee where FAge in(25,28,30);
+----------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+----------+-------+------+---------+
| DEV001 | Tom | 25 | 8300.00 |
| DEV002 | Jerry | 28 | 2300.80 |
| HR002 | Tina | 25 | 5200.36 |
| IT001 | Smith | 28 | 3900.00 |
| SALES002 | Kerry | 28 | 6200.00 |
+----------+-------+------+---------+
- 范圍值檢測(cè)
SQL中提供了一個(gè)專門用于范圍檢測(cè)的語(yǔ)句“BETWEEN AND”,它可以用于檢測(cè)一個(gè)值是否處于某個(gè)范圍中(包括范圍的邊界值)杉适。使用方法是BETWEEN 左范圍值 AND 右范圍值谎倔。
select * from T_Employee where FAge between 23 and 27;
+----------+-------+------+---------+
| FNumber | FName | FAge | FSalary |
+----------+-------+------+---------+
| DEV001 | Tom | 25 | 8300.00 |
| HR001 | Jane | 23 | 2200.88 |
| HR002 | Tina | 25 | 5200.36 |
| IT002 | NULL | 27 | 2800.00 |
| SALES001 | John | 23 | 5000.00 |
+----------+-------+------+---------+
數(shù)據(jù)庫(kù)系統(tǒng)對(duì)“BETWEEN AND”進(jìn)行了查詢優(yōu)化,使用該方式進(jìn)行范圍檢測(cè)將會(huì)比其他方式的性能更好猿推,所以范圍值檢測(cè)的時(shí)候優(yōu)先使用“BETWEEN AND”片习。
- 低效的“WHERE 1=1”
因?yàn)樘砑恿恕?=1”的過(guò)濾條件之后數(shù)據(jù)庫(kù)系統(tǒng)就沒(méi)有辦法使用索引等優(yōu)化策略,會(huì)對(duì)數(shù)據(jù)庫(kù)表的每行數(shù)據(jù)進(jìn)行掃描來(lái)比較滿足過(guò)濾條件的數(shù)據(jù)行蹬叭。如果表中的數(shù)據(jù)量很大的時(shí)候查詢的速度就會(huì)很慢藕咏。 - 數(shù)據(jù)分組
SQL中使用GROUP BY進(jìn)行分組,GROUP BY子句必須放在SELECT語(yǔ)句的后面秽五,如果有WHERE子句必須放在WHERE子句的后面孽查。
需要分組的所有的列都必須位于GROUP BY子句的列名列表中,也就是說(shuō)沒(méi)有出現(xiàn)在GROUP BY子句中的列(聚合函數(shù)除外)是不能放在SELECT語(yǔ)句后的列名列表中的筝蚕。
比如下面的查詢語(yǔ)句就是錯(cuò)誤的
select FAge,FSalary from T_Employee group by FAge;
因?yàn)檩敵龅慕Y(jié)果是采用的分組形式卦碾,但是每個(gè)員工的工資是不同的,所以不存在統(tǒng)一代表該組工資水平的FSalary起宽。
可以使用
select FAge,AVG(FSalary) from T_Employee group by FAge;
+------+--------------+
| FAge | AVG(FSalary) |
+------+--------------+
| 22 | 1200.000000 |
| 23 | 3600.440000 |
| 25 | 6750.180000 |
| 27 | 2800.000000 |
| 28 | 4133.600000 |
+------+--------------+
group by子句中可以指定多個(gè)列洲胖,只需要將多個(gè)列用逗號(hào)隔開(kāi)就行,指定多個(gè)列后坯沪,數(shù)據(jù)庫(kù)系統(tǒng)會(huì)按照定義的分組順序進(jìn)行逐層的分組绿映,首先按照第一個(gè)分組列進(jìn)行分組,然后在每個(gè)小組中再按照第二個(gè)分組列進(jìn)行再次分組,以此類推進(jìn)行逐層分組叉弦,從而實(shí)現(xiàn)組中組的效果丐一。
- 數(shù)據(jù)分組和聚合函數(shù)
使用group by分組后再使用聚合函數(shù)對(duì)分組的結(jié)果進(jìn)行統(tǒng)計(jì)。
例如淹冰,查看每個(gè)年齡段的員工的人數(shù)
select FAge,COUNT(*) from T_Employee group by FAge;
+------+----------+
| FAge | COUNT(*) |
+------+----------+
| 22 | 1 |
| 23 | 2 |
| 25 | 2 |
| 27 | 1 |
| 28 | 3 |
+------+----------+
進(jìn)行更細(xì)的分組
例如每個(gè)分公司的各個(gè)年齡段的員工數(shù)
select FSubCompany,FAge,COUNT(*) AS CountOfThisSubCompAge from T_Employee group by FSubCompany,FAge;
+-------------+------+-----------------------+
| FSubCompany | FAge | CountOfThisSubCompAge |
+-------------+------+-----------------------+
| NULL | 22 | 1 |
| NULL | 23 | 1 |
| NULL | 28 | 1 |
| Beijing | 23 | 1 |
| Beijing | 25 | 2 |
| Beijing | 28 | 1 |
| ShenZhen | 27 | 1 |
| ShenZhen | 28 | 1 |
+-------------+------+-----------------------+
- HAVING語(yǔ)句
有時(shí)候需要對(duì)部分分組進(jìn)行過(guò)濾库车,例如只檢索人數(shù)多余1個(gè)的年齡段。
如下的方式是錯(cuò)誤的
SELECT FAge,COUNT(*) AS CountOfThisAge FROM T_Employee GROUP BY FAge WHERE COUNT(*)>1
因?yàn)榫酆虾瘮?shù)是不能用在WHERE語(yǔ)句中的樱拴,必須使用HAVING子句來(lái)代替柠衍。
select FAge,count(*) as CountOfThisAge from T_Employee group by FAge having count(*)>1;
+------+----------------+
| FAge | CountOfThisAge |
+------+----------------+
| 23 | 2 |
| 25 | 2 |
| 28 | 3 |
+------+----------------+
HAVING語(yǔ)句和WHERE的語(yǔ)法幾乎一樣,但是GROUP BY子句要位于WHERE子句的后面晶乔,而HAVING子句要位于GROUP BY子句的后面珍坊。
另外需要注意的是HAVING語(yǔ)句中不能包含未分組的列名。
SELECT FAge,COUNT(*) AS CountOfThisAge FROM T_Employee GROUP BY FAge HAVING FName IS NOT NULL;
ERROR 1054 (42S22): Unknown column 'FName' in 'having clause'
可以修改為:
SELECT FAge,COUNT(*) AS CountOfThisAge FROM T_Employee WHERE FName IS NOT NULL GROUP BY FAge;
+------+----------------+
| FAge | CountOfThisAge |
+------+----------------+
| 22 | 1 |
| 23 | 2 |
| 25 | 2 |
| 28 | 3 |
+------+----------------+
- 限制結(jié)果集行數(shù)
各個(gè)主流數(shù)據(jù)庫(kù)中限制的結(jié)果集的行數(shù)的方法各不相同正罢。
MYSQL中提供了LIMIT關(guān)鍵字來(lái)限制返回的結(jié)果集阵漏。
語(yǔ)法格式是“LIMIT 首行行號(hào),要返回的結(jié)果集的最大數(shù)目”翻具。
例如取按工資降序從第二行開(kāi)始的最多五條記錄:
SELECT * FROM T_Employee ORDER BY FSalary LIMIT 2,5;
+----------+-------+------+---------+-------------+---------------+
| FNumber | FName | FAge | FSalary | FSubCompany | FDepartment |
+----------+-------+------+---------+-------------+---------------+
| DEV002 | Jerry | 28 | 2300.80 | ShenZhen | Development |
| IT002 | NULL | 27 | 2800.00 | ShenZhen | InfoTech |
| IT001 | Smith | 28 | 3900.00 | Beijing | InfoTech |
| SALES001 | John | 23 | 5000.00 | NULL | NULL |
| HR002 | Tina | 25 | 5200.36 | Beijing | HumanResource |
+----------+-------+------+---------+-------------+---------------+
- 抑制數(shù)據(jù)重復(fù)
可以使用DISTINCT關(guān)鍵字進(jìn)行重復(fù)數(shù)據(jù)的抑制履怯。使用語(yǔ)法是SELECT DISTINCT
DISTINCT是對(duì)整個(gè)結(jié)果集進(jìn)行數(shù)據(jù)重復(fù)抑制,而不是針對(duì)每一個(gè)列呛占。
select FDepartment from T_Employee;
+---------------+
| FDepartment |
+---------------+
| Development |
| Development |
| HumanResource |
| HumanResource |
| InfoTech |
| InfoTech |
| NULL |
| NULL |
| NULL |
+---------------+
select distinct FDepartment from T_Employee;
+---------------+
| FDepartment |
+---------------+
| Development |
| HumanResource |
| InfoTech |
| NULL |
+---------------+
select distinct FDepartment,FSubCompany from T_Employee;
+---------------+-------------+
| FDepartment | FSubCompany |
+---------------+-------------+
| Development | Beijing |
| Development | ShenZhen |
| HumanResource | Beijing |
| InfoTech | Beijing |
| InfoTech | ShenZhen |
| NULL | NULL |
+---------------+-------------+
- 計(jì)算字段
- 常量字段
select 'CowNew集團(tuán)' AS CompanyName,918000000 AS RegAmount,FName,FAge,FSubCompany from T_Employee;
+--------------+-----------+-------+------+-------------+
| CompanyName | RegAmount | FName | FAge | FSubCompany |
+--------------+-----------+-------+------+-------------+
| CowNew集團(tuán) | 918000000 | Tom | 25 | Beijing |
| CowNew集團(tuán) | 918000000 | Jerry | 28 | ShenZhen |
| CowNew集團(tuán) | 918000000 | Jane | 23 | Beijing |
| CowNew集團(tuán) | 918000000 | Tina | 25 | Beijing |
| CowNew集團(tuán) | 918000000 | Smith | 28 | Beijing |
| CowNew集團(tuán) | 918000000 | NULL | 27 | ShenZhen |
| CowNew集團(tuán) | 918000000 | John | 23 | NULL |
| CowNew集團(tuán) | 918000000 | Kerry | 28 | NULL |
| CowNew集團(tuán) | 918000000 | Stone | 22 | NULL |
+--------------+-----------+-------+------+-------------+
'CowNew集團(tuán)' 和918000000就是常量字段
- 字段間計(jì)算
select FNumber,FName,FAge*FSalary AS FSalaryIndex from T_Employee;
+----------+-------+--------------+
| FNumber | FName | FSalaryIndex |
+----------+-------+--------------+
| DEV001 | Tom | 207500.00 |
| DEV002 | Jerry | 64422.40 |
| HR001 | Jane | 50620.24 |
| HR002 | Tina | 130009.00 |
| IT001 | Smith | 109200.00 |
| IT002 | NULL | 75600.00 |
| SALES001 | John | 115000.00 |
| SALES002 | Kerry | 173600.00 |
| SALES003 | Stone | 26400.00 |
+----------+-------+--------------+
計(jì)算字段也可以在WHERE語(yǔ)句或者UPDATE虑乖、DELETE中使用。
select * from T_Employee where FSalary/(FAge - 21)>1000 ;
+----------+-------+------+---------+-------------+---------------+
| FNumber | FName | FAge | FSalary | FSubCompany | FDepartment |
+----------+-------+------+---------+-------------+---------------+
| DEV001 | Tom | 25 | 8300.00 | Beijing | Development |
| HR001 | Jane | 23 | 2200.88 | Beijing | HumanResource |
| HR002 | Tina | 25 | 5200.36 | Beijing | HumanResource |
| SALES001 | John | 23 | 5000.00 | NULL | NULL |
| SALES003 | Stone | 22 | 1200.00 | NULL | NULL |
+----------+-------+------+---------+-------------+---------------+
- 數(shù)據(jù)處理函數(shù)
例如計(jì)算字符串長(zhǎng)度的函數(shù)LENGTH
select FName,LENGTH(FName) from T_Employee;
+-------+---------------+
| FName | LENGTH(FName) |
+-------+---------------+
| Tom | 3 |
| Jerry | 5 |
| Jane | 4 |
| Tina | 4 |
| Smith | 5 |
| NULL | NULL |
| John | 4 |
| Kerry | 5 |
| Stone | 5 |
+-------+---------------+
取字符串的子串函數(shù)晾虑,SUBSTRING(字符串疹味,起始位置(從1開(kāi)始計(jì)數(shù)),子串的長(zhǎng)度)
select FName,SUBSTRING(FName,1,2) from T_Employee;
+-------+----------------------+
| FName | SUBSTRING(FName,1,2) |
+-------+----------------------+
| Tom | To |
| Jerry | Je |
| Jane | Ja |
| Tina | Ti |
| Smith | Sm |
| NULL | NULL |
| John | Jo |
| Kerry | Ke |
| Stone | St |
+-------+----------------------+
字符串的拼接
在有的數(shù)據(jù)庫(kù)系統(tǒng)的SQL語(yǔ)法中雙引號(hào)有其他的含義帜篇,然而所有的數(shù)據(jù)庫(kù)系統(tǒng)都支持使用單引號(hào)包圍的形式定義的字符串糙捺,所以建議使用單引號(hào)包圍的形式來(lái)定義字符串。
MYSQL中可以使用“+”進(jìn)行字符串拼接笙隙,在使用“+”號(hào)的時(shí)候洪灯,MYSQL會(huì)嘗試兩個(gè)字符串轉(zhuǎn)換成數(shù)字類型(如果轉(zhuǎn)換失敗則認(rèn)為字段值為0),然后進(jìn)行字段的加法運(yùn)算竟痰,因此我們會(huì)發(fā)現(xiàn)如下的例子中“12”+“23”得到的不是1223而是35.
select '12'+'23',FAge + '1' from T_Employee;
+-----------+------------+
| '12'+'23' | FAge + '1' |
+-----------+------------+
| 35 | 26 |
| 35 | 29 |
| 35 | 24 |
| 35 | 26 |
| 35 | 29 |
| 35 | 28 |
| 35 | 24 |
| 35 | 29 |
| 35 | 23 |
+-----------+------------+
select 'abc'+'123',FAge from T_Employee;
+-------------+------+
| 'abc'+'123' | FAge |
+-------------+------+
| 123 | 25 |
| 123 | 28 |
| 123 | 23 |
| 123 | 25 |
| 123 | 28 |
| 123 | 27 |
| 123 | 23 |
| 123 | 28 |
| 123 | 22 |
+-------------+------+
select 'abc'+'d',FAge from T_Employee;
+-----------+------+
| 'abc'+'d' | FAge |
+-----------+------+
| 0 | 25 |
| 0 | 28 |
| 0 | 23 |
| 0 | 25 |
| 0 | 28 |
| 0 | 27 |
| 0 | 23 |
| 0 | 28 |
| 0 | 22 |
+-----------+------+
MYSQL中也可以使用CONCAT函數(shù)進(jìn)行字符串的拼接签钩,
CONCAT函數(shù)支持一個(gè)或者多個(gè)參數(shù),參數(shù)類型可以是字符串類型也可以是非字符串類型坏快,對(duì)于非字符串類型的參數(shù)MYSQL將嘗試將其轉(zhuǎn)換成字符串類型铅檩。
例如:
select CONCAT('工號(hào)為:',FNumber,'的員工的幸福指數(shù):',FSalary/(FAge-21)) from T_Employee;
MYSQL中還提供了支持在待拼接的字符串之間加入指定的分隔符的函數(shù)CONCAT_WS。
- 聯(lián)合結(jié)果集
有時(shí)候需要組合兩個(gè)完全不同的結(jié)果集莽鸿,而這兩個(gè)查詢結(jié)果集之間沒(méi)有必然的聯(lián)系昧旨。SQL中可以使用UNION將兩個(gè)或多個(gè)查詢結(jié)果集聯(lián)合為一個(gè)結(jié)果集拾给。
UNION運(yùn)算符要放置在兩個(gè)查詢之間
例如查詢公司所有員工的信息,包括正式員工和臨時(shí)員工的信息
select FNumber,FName,FAge from T_Employee UNION select FIdCardNumber,FName,FAge from T_TempEmployee;
+---------------+---------+------+
| FNumber | FName | FAge |
+---------------+---------+------+
| DEV001 | Tom | 25 |
| DEV002 | Jerry | 28 |
| HR001 | Jane | 23 |
| HR002 | Tina | 25 |
| IT001 | Smith | 28 |
| IT002 | NULL | 27 |
| SALES001 | John | 23 |
| SALES002 | Kerry | 28 |
| SALES003 | Stone | 22 |
| 1234567890121 | Sarani | 33 |
| 1234567890122 | Tom | 26 |
| 1234567890123 | Yalaha | 38 |
| 1234567890124 | Tina | 26 |
| 1234567890125 | Konkaya | 29 |
| 1234567890126 | Fotifa | 46 |
+---------------+---------+------+
- 聯(lián)合結(jié)果集的原則
使用UNION的兩個(gè)原則:一兔沃、每個(gè)結(jié)果集必須有相同的列數(shù)蒋得;二、每個(gè)結(jié)果集的列必須類型向容(相同類型或者能夠轉(zhuǎn)換為同一種數(shù)據(jù)類型)乒疏。
select FNumber,FName,FAge from T_Employee UNION select FIdCardNumber,FAge,FName from T_TempEmployee;
+---------------+-------+---------+
| FNumber | FName | FAge |
+---------------+-------+---------+
| DEV001 | Tom | 25 |
| DEV002 | Jerry | 28 |
| HR001 | Jane | 23 |
| HR002 | Tina | 25 |
| IT001 | Smith | 28 |
| IT002 | NULL | 27 |
| SALES001 | John | 23 |
| SALES002 | Kerry | 28 |
| SALES003 | Stone | 22 |
| 1234567890121 | 33 | Sarani |
| 1234567890122 | 26 | Tom |
| 1234567890123 | 38 | Yalaha |
| 1234567890124 | 26 | Tina |
| 1234567890125 | 29 | Konkaya |
| 1234567890126 | 46 | Fotifa |
+---------------+-------+---------+
上面的結(jié)果中可以看出將FAge轉(zhuǎn)換成文本類型
但是有些數(shù)據(jù)庫(kù)要求必須類型相同额衙,所以最好保證結(jié)果集的每個(gè)對(duì)應(yīng)列的數(shù)據(jù)類型完全相同。
- UNION ALL
使用UNION合并兩個(gè)查詢結(jié)果集時(shí)怕吴,其中完全重復(fù)的數(shù)據(jù)會(huì)被合并為一條入偷。
如果需要返回所有的記錄而不是重復(fù)的數(shù)據(jù)合并就需要使用UNION ALL
函數(shù)
省略不寫(xiě),需要時(shí)再查文檔
索引與約束
索引用來(lái)提高檢索數(shù)據(jù)的速度械哟,約束用來(lái)保證數(shù)據(jù)的完整行。
1.非空約束
需要禁止字段為空的話殿雪,就需要使用非空約束
CREATE TABLE T_Person (
FNumber VARCHAR(20) NOT NULL ,(非空約束)
FName VARCHAR(20),
FAge INT
)
- 唯一約束
用于防止一個(gè)特定的列中兩個(gè)記錄有一樣的值暇咆。
CREATE TABLE T_Person( FNumber VARCHAR(20) UNIQUE, FName VARCHAR(20), FAge INT);
INSERT INTO T_Person (FNumber, FName, FAge) VALUES ( '1' , 'kingchou', 20);
INSERT INTO T_Person (FNumber, FName, FAge) VALUES ( '2' , 'stef', 22);
INSERT INTO T_Person (FNumber, FName, FAge) VALUES ( '3' , 'long', 26);
INSERT INTO T_Person (FNumber, FName, FAge) VALUES ( '4' , 'yangzk', 27);
INSERT INTO T_Person (FNumber, FName, FAge) VALUES ( '5' , 'beansoft', 26);
select * from T_Person;
+---------+----------+------+
| FNumber | FName | FAge |
+---------+----------+------+
| 1 | kingchou | 20 |
| 2 | stef | 22 |
| 3 | long | 26 |
| 4 | yangzk | 27 |
| 5 | beansoft | 26 |
+---------+----------+------+
INSERT INTO T_Person(FNumber,FName,FAge) VALUES('2','kitty',20);
ERROR 1062 (23000): Duplicate entry '2' for key 'FNumber'
上面講的是定義單字段唯一約束
多字段唯一約束的定義蘇耀在所有字段列表的后面,語(yǔ)法格式如下:
CONSTRAINT 約束名 UNIQUE(字段1丙曙,字段2爸业,.......)
- CHECK約束
CHECK約束用來(lái)檢查輸入到數(shù)據(jù)庫(kù)中的值是否滿足一個(gè)條件,如果不滿足這個(gè)條件則對(duì)數(shù)據(jù)庫(kù)的修改就不會(huì)成功亏镰,一張表中可以存在多個(gè)CHECK約束扯旷。
CREATE TABLE T_Person
(
FNumber VARCHAR(20),
FName VARCHAR(20),
FAge INT CHECK(FAge>0),
FWorkYear INT CHECK(FWorkYear>0)
);
INSERT INTO T_Person(FNumber, FName, FAge, FWorkYear)
VALUES('001','John',25,-3)
因?yàn)樵O(shè)置的是FWorkYear大于0,所以插入-3會(huì)報(bào)錯(cuò)索抓。
還有一種在所有字段后加檢查約束條件的
CONSTRAINT 約束名 CHECK(約束條件);
- 主鍵約束
主鍵必須能夠唯一標(biāo)識(shí)一條記錄钧忽,主鍵字段的值必須是唯一的,而且其中不能包含NULL值逼肯。
由單一字段組成的主鍵可以在字段定義之后添加PRIMARY KEY就可以耸黑。
如果是由多個(gè)字段組成的就稱為聯(lián)合主鍵,定義的格式是:
CONSTRAINT 主鍵名 PRIMARY KEY(字段1篮幢,字段2.....)
也可以使用
ALTER TABLE 表格名 ADD CONSTRAINT 主鍵名 PRIMARY KEY(字段1大刊,字段2.......) - 外鍵約束
定義格式是:
FOREIGN KEY 外鍵字段 REFERENCES 外鍵表名(外鍵表的主鍵字段)
表連接
select * from T_Order;
+-----+---------+--------+-------------+---------+
| FId | FNumber | FPrice | FCustomerId | FTypeId |
+-----+---------+--------+-------------+---------+
| 1 | K001 | 100.00 | 1 | 1 |
| 2 | K002 | 200.00 | 1 | 1 |
| 3 | T003 | 300.00 | 1 | 2 |
| 4 | N002 | 100.00 | 2 | 2 |
| 5 | N003 | 500.00 | 3 | 4 |
| 6 | T001 | 300.00 | 4 | 3 |
| 7 | T002 | 100.00 | NULL | 1 |
+-----+---------+--------+-------------+---------+
select * from T_OrderType;
+-----+-----------------+
| FId | FName |
+-----+-----------------+
| 1 | MarketOrder |
| 2 | LimitOrder |
| 3 | Stop Order |
| 4 | StopLimit Order |
+-----+-----------------+
select * from T_Customer;
+-----+-------+------+
| FId | FName | FAge |
+-----+-------+------+
| 1 | TOM | 21 |
| 2 | MIKE | 24 |
| 3 | JACK | 30 |
| 4 | TOM | 25 |
| 5 | LINDA | NULL |
+-----+-------+------+
從多張表中查詢數(shù)據(jù),可以使用表連接JOIN三椿,表連接有多種不同的類型缺菌,交叉連接(CROSS JOIN)、內(nèi)連接(INNER JOIN)搜锰、外連接(OUTTER JOIN)伴郁。
- 內(nèi)連接
語(yǔ)法格式如下:
INNER JOIN tableName ON condition
tableName為被連接的表名,condition為連接時(shí)的條件纽乱。
select FNumber,FPrice from T_Order INNER JOIN T_Customer ON FCustomerId = T_Customer.FId WHERE T_Customer.FName='TOM';
+---------+--------+
| FNumber | FPrice |
+---------+--------+
| K001 | 100.00 |
| K002 | 200.00 |
| T003 | 300.00 |
| T001 | 300.00 |
+---------+--------+
為了避免列名歧義并且提高可讀性蛾绎,在使用表連接的時(shí)候建議要顯示列所屬的表。
select T_Order.FId,T_Order.FNumber,T_Order.FPrice,T_Customer.FId,T_Customer.FName,T_Customer.FAge from T_Order INNER JOIN T_Customer ON T_Order.FCustomerId = T_Customer.FId;
+-----+---------+--------+-----+-------+------+
| FId | FNumber | FPrice | FId | FName | FAge |
+-----+---------+--------+-----+-------+------+
| 1 | K001 | 100.00 | 1 | TOM | 21 |
| 2 | K002 | 200.00 | 1 | TOM | 21 |
| 3 | T003 | 300.00 | 1 | TOM | 21 |
| 4 | N002 | 100.00 | 2 | MIKE | 24 |
| 5 | N003 | 500.00 | 3 | JACK | 30 |
| 6 | T001 | 300.00 | 4 | TOM | 25 |
+-----+---------+--------+-----+-------+------+
在大多數(shù)的數(shù)據(jù)庫(kù)系統(tǒng)中,INNER JOIN中的INNER是可以省略的租冠,INNER JOIN是默認(rèn)的連接方式鹏倘。
可以使用表的別名來(lái)簡(jiǎn)化SQL語(yǔ)句編寫(xiě)
select o.FId,o.FNumber,o.FPrice,c.FId,c.FName,c.FAge from T_Order o JOIN T_Customer c ON o.FCustomerId = c.FId;
+-----+---------+--------+-----+-------+------+
| FId | FNumber | FPrice | FId | FName | FAge |
+-----+---------+--------+-----+-------+------+
| 1 | K001 | 100.00 | 1 | TOM | 21 |
| 2 | K002 | 200.00 | 1 | TOM | 21 |
| 3 | T003 | 300.00 | 1 | TOM | 21 |
| 4 | N002 | 100.00 | 2 | MIKE | 24 |
| 5 | N003 | 500.00 | 3 | JACK | 30 |
| 6 | T001 | 300.00 | 4 | TOM | 25 |
+-----+---------+--------+-----+-------+------+
- 不等值連接
到目前,我們例子中的所有連接都是等值連接,也就是on子句包含一個(gè)等號(hào)運(yùn)算宠默。還有一種不等值連接黔寇,在連接的條件中可以使用小于(<)、大于(>)捏题、不等于(<>)、LIKE肉渴、BETWEEN AND等運(yùn)算符公荧。
select T_Order.FNumber,T_Order.FPrice,T_Customer.FName,T_Customer.FAge from T_Order INNER JOIN T_Customer ON T_Order.FPrice<T_Customer.FAge*5;
+---------+--------+-------+------+
| FNumber | FPrice | FName | FAge |
+---------+--------+-------+------+
| K001 | 100.00 | TOM | 21 |
| K001 | 100.00 | MIKE | 24 |
| K001 | 100.00 | JACK | 30 |
| K001 | 100.00 | TOM | 25 |
| N002 | 100.00 | TOM | 21 |
| N002 | 100.00 | MIKE | 24 |
| N002 | 100.00 | JACK | 30 |
| N002 | 100.00 | TOM | 25 |
| T002 | 100.00 | TOM | 21 |
| T002 | 100.00 | MIKE | 24 |
| T002 | 100.00 | JACK | 30 |
| T002 | 100.00 | TOM | 25 |
+---------+--------+-------+------+
不等值連接產(chǎn)生了大量的查詢結(jié)果,因?yàn)樗菍?duì)被連接的兩張表做了笛卡爾積運(yùn)算同规,所以如果想看客戶對(duì)應(yīng)的訂單循狰,就需要在不等值連接后面加上等值連接匹配條件。
select T_Order.FNumber,T_Order.FPrice,T_Customer.FName,T_Customer.FAge from T_Order INNER JOIN T_Customer ON T_Order.FPrice<T_Customer.FAge*5 AND T_Order.FCustomerId=T_Customer.FId;
+---------+--------+-------+------+
| FNumber | FPrice | FName | FAge |
+---------+--------+-------+------+
| K001 | 100.00 | TOM | 21 |
| N002 | 100.00 | MIKE | 24 |
+---------+--------+-------+------+
- 交叉連接
交叉連接不存在on連接條件券勺,交叉連接會(huì)將涉及到的所有表中的所有記錄都包含在結(jié)果集中绪钥。有兩種實(shí)現(xiàn)方式,分別是顯示和隱式的关炼。
隱式連接是在SELECT 語(yǔ)句的FROM語(yǔ)句后將要進(jìn)行交叉連接的表名列出來(lái)程腹。
select c.FId,c.FName,c.FAge,o.FId,o.FNumber,o.FPrice from T_Customer c,T_Order o;
+-----+-------+------+-----+---------+--------+
| FId | FName | FAge | FId | FNumber | FPrice |
+-----+-------+------+-----+---------+--------+
| 1 | TOM | 21 | 1 | K001 | 100.00 |
| 2 | MIKE | 24 | 1 | K001 | 100.00 |
| 3 | JACK | 30 | 1 | K001 | 100.00 |
| 4 | TOM | 25 | 1 | K001 | 100.00 |
| 5 | LINDA | NULL | 1 | K001 | 100.00 |
| 1 | TOM | 21 | 2 | K002 | 200.00 |
| 2 | MIKE | 24 | 2 | K002 | 200.00 |
| 3 | JACK | 30 | 2 | K002 | 200.00 |
| 4 | TOM | 25 | 2 | K002 | 200.00 |
| 5 | LINDA | NULL | 2 | K002 | 200.00 |
| 1 | TOM | 21 | 3 | T003 | 300.00 |
| 2 | MIKE | 24 | 3 | T003 | 300.00 |
| 3 | JACK | 30 | 3 | T003 | 300.00 |
| 4 | TOM | 25 | 3 | T003 | 300.00 |
| 5 | LINDA | NULL | 3 | T003 | 300.00 |
| 1 | TOM | 21 | 4 | N002 | 100.00 |
| 2 | MIKE | 24 | 4 | N002 | 100.00 |
| 3 | JACK | 30 | 4 | N002 | 100.00 |
| 4 | TOM | 25 | 4 | N002 | 100.00 |
| 5 | LINDA | NULL | 4 | N002 | 100.00 |
| 1 | TOM | 21 | 5 | N003 | 500.00 |
| 2 | MIKE | 24 | 5 | N003 | 500.00 |
| 3 | JACK | 30 | 5 | N003 | 500.00 |
| 4 | TOM | 25 | 5 | N003 | 500.00 |
| 5 | LINDA | NULL | 5 | N003 | 500.00 |
| 1 | TOM | 21 | 6 | T001 | 300.00 |
| 2 | MIKE | 24 | 6 | T001 | 300.00 |
| 3 | JACK | 30 | 6 | T001 | 300.00 |
| 4 | TOM | 25 | 6 | T001 | 300.00 |
| 5 | LINDA | NULL | 6 | T001 | 300.00 |
| 1 | TOM | 21 | 7 | T002 | 100.00 |
| 2 | MIKE | 24 | 7 | T002 | 100.00 |
| 3 | JACK | 30 | 7 | T002 | 100.00 |
| 4 | TOM | 25 | 7 | T002 | 100.00 |
| 5 | LINDA | NULL | 7 | T002 | 100.00 |
+-----+-------+------+-----+---------+--------+
顯示的交叉連接是使用CROSS JOIN關(guān)鍵字
select c.FId,c.FName,c.FAge,o.FId,o.FNumber,o.FPrice from T_Customer c cross join T_Order o;
+-----+-------+------+-----+---------+--------+
| FId | FName | FAge | FId | FNumber | FPrice |
+-----+-------+------+-----+---------+--------+
| 1 | TOM | 21 | 1 | K001 | 100.00 |
| 2 | MIKE | 24 | 1 | K001 | 100.00 |
| 3 | JACK | 30 | 1 | K001 | 100.00 |
| 4 | TOM | 25 | 1 | K001 | 100.00 |
| 5 | LINDA | NULL | 1 | K001 | 100.00 |
| 1 | TOM | 21 | 2 | K002 | 200.00 |
| 2 | MIKE | 24 | 2 | K002 | 200.00 |
| 3 | JACK | 30 | 2 | K002 | 200.00 |
| 4 | TOM | 25 | 2 | K002 | 200.00 |
| 5 | LINDA | NULL | 2 | K002 | 200.00 |
| 1 | TOM | 21 | 3 | T003 | 300.00 |
| 2 | MIKE | 24 | 3 | T003 | 300.00 |
| 3 | JACK | 30 | 3 | T003 | 300.00 |
| 4 | TOM | 25 | 3 | T003 | 300.00 |
| 5 | LINDA | NULL | 3 | T003 | 300.00 |
| 1 | TOM | 21 | 4 | N002 | 100.00 |
| 2 | MIKE | 24 | 4 | N002 | 100.00 |
| 3 | JACK | 30 | 4 | N002 | 100.00 |
| 4 | TOM | 25 | 4 | N002 | 100.00 |
| 5 | LINDA | NULL | 4 | N002 | 100.00 |
| 1 | TOM | 21 | 5 | N003 | 500.00 |
| 2 | MIKE | 24 | 5 | N003 | 500.00 |
| 3 | JACK | 30 | 5 | N003 | 500.00 |
| 4 | TOM | 25 | 5 | N003 | 500.00 |
| 5 | LINDA | NULL | 5 | N003 | 500.00 |
| 1 | TOM | 21 | 6 | T001 | 300.00 |
| 2 | MIKE | 24 | 6 | T001 | 300.00 |
| 3 | JACK | 30 | 6 | T001 | 300.00 |
| 4 | TOM | 25 | 6 | T001 | 300.00 |
| 5 | LINDA | NULL | 6 | T001 | 300.00 |
| 1 | TOM | 21 | 7 | T002 | 100.00 |
| 2 | MIKE | 24 | 7 | T002 | 100.00 |
| 3 | JACK | 30 | 7 | T002 | 100.00 |
| 4 | TOM | 25 | 7 | T002 | 100.00 |
| 5 | LINDA | NULL | 7 | T002 | 100.00 |
+-----+-------+------+-----+---------+--------+
- 自連接
上面講的例子都是不同表之間的連接,其實(shí)可以同一張表進(jìn)行連接也就是自連接
select o1.FId,o1.FNumber,o1.FPrice,o2.FId,o2.FNumber,o2.FPrice from T_Order o1 JOIN T_Order o2 ON o1.FTypeId=o2.FTypeId AND o1.FId<o2.FId;
+-----+---------+--------+-----+---------+--------+
| FId | FNumber | FPrice | FId | FNumber | FPrice |
+-----+---------+--------+-----+---------+--------+
| 1 | K001 | 100.00 | 2 | K002 | 200.00 |
| 1 | K001 | 100.00 | 7 | T002 | 100.00 |
| 2 | K002 | 200.00 | 7 | T002 | 100.00 |
| 3 | T003 | 300.00 | 4 | N002 | 100.00 |
+-----+---------+--------+-----+---------+--------+
- 外部連接
select * from T_Order;
+-----+---------+--------+-------------+---------+
| FId | FNumber | FPrice | FCustomerId | FTypeId |
+-----+---------+--------+-------------+---------+
| 1 | K001 | 100.00 | 1 | 1 |
| 2 | K002 | 200.00 | 1 | 1 |
| 3 | T003 | 300.00 | 1 | 2 |
| 4 | N002 | 100.00 | 2 | 2 |
| 5 | N003 | 500.00 | 3 | 4 |
| 6 | T001 | 300.00 | 4 | 3 |
| 7 | T002 | 100.00 | NULL | 1 |
+-----+---------+--------+-------------+---------+
select * from T_Customer;
+-----+-------+------+
| FId | FName | FAge |
+-----+-------+------+
| 1 | TOM | 21 |
| 2 | MIKE | 24 |
| 3 | JACK | 30 |
| 4 | TOM | 25 |
| 5 | LINDA | NULL |
+-----+-------+------+
使用內(nèi)部連接將訂單以及對(duì)應(yīng)的客戶信息顯示出來(lái)
select o.FNumber,o.FPrice,o.FCustomerId,c.FName,c.FAge from T_Order o JOIN T_Customer c ON o.FCustomerId=c.FId;
+---------+--------+-------------+-------+------+
| FNumber | FPrice | FCustomerId | FName | FAge |
+---------+--------+-------------+-------+------+
| K001 | 100.00 | 1 | TOM | 21 |
| K002 | 200.00 | 1 | TOM | 21 |
| T003 | 300.00 | 1 | TOM | 21 |
| N002 | 100.00 | 2 | MIKE | 24 |
| N003 | 500.00 | 3 | JACK | 30 |
| T001 | 300.00 | 4 | TOM | 25 |
+---------+--------+-------------+-------+------+
可以看到T002這個(gè)訂單沒(méi)有顯示出來(lái)儒拂,因?yàn)槠銯CustomerId為NULL寸潦,找不到對(duì)應(yīng)的客戶信息。
有時(shí)候需要顯示出這些NULL值的數(shù)據(jù)社痛,就需要使用外部連接
外部連接分為左外部連接甸祭、右外部連接和全外部連接。
左外部連接:返回左表中的全部數(shù)據(jù)
右外部連接:返回右表中的全部數(shù)據(jù)
全外部連接:左右表中的數(shù)據(jù)都返回
左外部連接:
select o.FNumber,o.FPrice,o.FCustomerId,c.FName,c.FAge from T_Order o LEFT JOIN T_Customer c ON o.FCustomerId=c.FId;
+---------+--------+-------------+-------+------+
| FNumber | FPrice | FCustomerId | FName | FAge |
+---------+--------+-------------+-------+------+
| K001 | 100.00 | 1 | TOM | 21 |
| K002 | 200.00 | 1 | TOM | 21 |
| T003 | 300.00 | 1 | TOM | 21 |
| N002 | 100.00 | 2 | MIKE | 24 |
| N003 | 500.00 | 3 | JACK | 30 |
| T001 | 300.00 | 4 | TOM | 25 |
| T002 | 100.00 | NULL | NULL | NULL |
+---------+--------+-------------+-------+------+
右外部連接
select o.FNumber,o.FPrice,o.FCustomerId,c.FName,c.FAge from T_Order o RIGHT JOIN T_Customer c ON o.FCustomerId=c.FId;
+---------+--------+-------------+-------+------+
| FNumber | FPrice | FCustomerId | FName | FAge |
+---------+--------+-------------+-------+------+
| K001 | 100.00 | 1 | TOM | 21 |
| K002 | 200.00 | 1 | TOM | 21 |
| T003 | 300.00 | 1 | TOM | 21 |
| N002 | 100.00 | 2 | MIKE | 24 |
| N003 | 500.00 | 3 | JACK | 30 |
| T001 | 300.00 | 4 | TOM | 25 |
| NULL | NULL | NULL | LINDA | NULL |
+---------+--------+-------------+-------+------+
全外部連接
select o.FNumber,o.FPrice,o.FCustomerId,c.FName,c.FAge from T_Order o FULL OUTER JOIN T_Customer c ON o.FCustomerId=c.FId;
MYSQL不支持使用FULL OUTER JOIN褥影,可以使用左外部連接和右外部連接來(lái)模擬全外部連接池户。
select o.FNumber,o.FPrice,o.FCustomerId,c.FName,c.FAge from T_Order o LEFT JOIN T_Customer c ON o.FCustomerId=c.FId
UNION
select o.FNumber,o.FPrice,o.FCustomerId,c.FName,c.FAge from T_Order o RIGHT JOIN T_Customer c ON o.FCustomerId=c.FId;
+---------+--------+-------------+-------+------+
| FNumber | FPrice | FCustomerId | FName | FAge |
+---------+--------+-------------+-------+------+
| K001 | 100.00 | 1 | TOM | 21 |
| K002 | 200.00 | 1 | TOM | 21 |
| T003 | 300.00 | 1 | TOM | 21 |
| N002 | 100.00 | 2 | MIKE | 24 |
| N003 | 500.00 | 3 | JACK | 30 |
| T001 | 300.00 | 4 | TOM | 25 |
| T002 | 100.00 | NULL | NULL | NULL |
| NULL | NULL | NULL | LINDA | NULL |
+---------+--------+-------------+-------+------+
子查詢
SQL語(yǔ)句允許將一個(gè)查詢語(yǔ)句作為一個(gè)結(jié)果集供其他SQL語(yǔ)句調(diào)用,被當(dāng)作結(jié)果集的查詢語(yǔ)句被稱為子查詢凡怎,所有使用表的地方幾乎都可以使用子查詢來(lái)代替校焦。
CREATE TABLE T_Reader (FId INT NOT NULL ,FName VARCHAR(50),FYearOfBirth INT,FCity VARCHAR(50),FProvince VARCHAR(50), FYearOfJoin INT);
CREATE TABLE T_Book (FId INT NOT NULL ,FName VARCHAR(50),FYearPublished INT,FCategoryId INT);
CREATE TABLE T_Category (FId INT NOT NULL ,FName VARCHAR(50));
CREATE TABLE T_ReaderFavorite (FCategoryId INT,FReaderId INT);
select * from T_Reader;
+-----+-------+--------------+-----------+-----------+-------------+
| FId | FName | FYearOfBirth | FCity | FProvince | FYearOfJoin |
+-----+-------+--------------+-----------+-----------+-------------+
| 1 | Tom | 1979 | TangShan | Hebei | 2003 |
| 2 | Sam | 1981 | LangFang | Hebei | 2001 |
| 3 | Jerry | 1966 | DongGuan | GuangDong | 1995 |
| 4 | Lily | 1972 | JiaXing | ZheJiang | 2005 |
| 5 | Marry | 1985 | BeiJing | BeiJing | 1999 |
| 6 | Kelly | 1977 | ZhuZhou | HuNan | 1995 |
| 7 | Tim | 1982 | YongZhou | HuNan | 2001 |
| 8 | King | 1979 | JiNan | ShanDong | 1997 |
| 9 | John | 1979 | QingDao | ShanDong | 2003 |
| 10 | Lucy | 1978 | LuoYang | HeNan | 1996 |
| 11 | July | 1983 | ZhuMaDian | HeNan | 1999 |
| 12 | Fige | 1981 | JinCheng | ShanXi | 2003 |
+-----+-------+--------------+-----------+-----------+-------------+
select * from T_Book;
+-----+------------------------+----------------+-------------+
| FId | FName | FYearPublished | FCategoryId |
+-----+------------------------+----------------+-------------+
| 1 | About J2EE | 2005 | 4 |
| 2 | Learning Hibernate | 2003 | 4 |
| 3 | Two Cites | 1999 | 1 |
| 4 | Jane Eyre | 2001 | 1 |
| 5 | Oliver Twist | 2002 | 1 |
| 6 | History of China | 1982 | 2 |
| 7 | History of England | 1860 | 2 |
| 8 | History of America | 1700 | 2 |
| 9 | History of The World | 2008 | 2 |
| 10 | Atom | 1930 | 3 |
| 11 | RELATIVITY | 1945 | 3 |
| 12 | Computer | 1970 | 3 |
| 13 | Astronomy | 1971 | 3 |
| 14 | How To Singing | 1771 | 5 |
| 15 | DaoDeJing | 2001 | 6 |
| 16 | Obedience to Authority | 1995 | 6 |
+-----+------------------------+----------------+-------------+
select * from T_Category;
+-----+------------+
| FId | FName |
+-----+------------+
| 1 | Story |
| 2 | History |
| 3 | Theory |
| 4 | Technology |
| 5 | Art |
| 6 | Philosophy |
+-----+------------+
select * from T_ReaderFavorite;
+-------------+-----------+
| FCategoryId | FReaderId |
+-------------+-----------+
| 2 | 11 |
| 1 | 12 |
| 3 | 1 |
| 1 | 3 |
| 4 | 4 |
+-------------+-----------+
子查詢有兩種分別是,一種是只返回一個(gè)單值的子查詢统倒,另一種是返回一列值的子查詢寨典。
- 單值子查詢
select 1 AS f1,2,(SELECT MIN(FYearPublished) FROM T_Book),(SELECT MAX(FYearPublished) FROM T_Book) AS f4 from DUAL;
+----+---+------------------------------------------+------+
| f1 | 2 | (SELECT MIN(FYearPublished) FROM T_Book) | f4 |
+----+---+------------------------------------------+------+
| 1 | 2 | 1700 | 2008 |
+----+---+------------------------------------------+------+
- 列值子查詢
列值子查詢會(huì)返回一個(gè)多行多列的結(jié)果集,可以將該結(jié)果集看作一個(gè)臨時(shí)的表房匆。
列值子查詢可以用在SELECT的FROM子句耸成、INSERT語(yǔ)句报亩、連接和IN子句等。
數(shù)據(jù)庫(kù)高級(jí)話題
- SQL調(diào)優(yōu)
- 索引
索引是數(shù)據(jù)庫(kù)調(diào)優(yōu)的最根本的優(yōu)化方法井氢,一般是在檢索時(shí)候使用的字段上創(chuàng)建索引弦追。 - 常用的優(yōu)化方法
1、在經(jīng)常需要檢索的字段上創(chuàng)建索引
2花竞、使用預(yù)編譯查詢
3劲件、select語(yǔ)句中避免使用,只檢索需要用到的列约急,即使需要檢索所有的列零远,也不要使用,因?yàn)镈BMS在解析的過(guò)程中還要將*依次轉(zhuǎn)換成所有的列名厌蔽,會(huì)消耗更多的時(shí)間牵辣。
4、盡量將多條SQL語(yǔ)句壓縮到一句SQL中奴饮,因?yàn)槊看螆?zhí)行SQL的時(shí)候都需要建立網(wǎng)絡(luò)連接服猪、進(jìn)行SQL優(yōu)化、發(fā)送結(jié)果等過(guò)程拐云,這個(gè)過(guò)程是非常耗時(shí)的。
5近她、用WHERE子句替換HAVING叉瘩,因?yàn)镠AVING只會(huì)在檢索出所有記錄之后才對(duì)結(jié)果集進(jìn)行過(guò)濾。
6粘捎、使用表的別名薇缅,當(dāng)SQL連接多個(gè)表時(shí),使用別名可以減少語(yǔ)法錯(cuò)誤攒磨。
7泳桦、避免在索引列上使用計(jì)算,如果索引列是計(jì)算或者函數(shù)的一部分娩缰,那么DBMS優(yōu)化器將不再使用索引而進(jìn)行全表掃描灸撰。
8、 如果執(zhí)行一系列操作是以原子形式完成的拼坎,就需要使用事務(wù)浮毯。