一、數(shù)據(jù)類型
1、數(shù)字
| 類型 | 大小 | 說明 |
|---|---|---|
| TINYINT | 1字節(jié) | 小整數(shù)(8個二進(jìn)制位,負(fù)的128到正的127) |
| SMALLINT | 2字節(jié) | 普通整數(shù)(16個二進(jìn)制位,負(fù)的2的16次冪到正的2的16次冪) |
| MEDIUMINT | 3字節(jié) | 普通整數(shù) |
| INT | 4字節(jié) | 較大整數(shù)(最常用) |
| BIGINT | 8字節(jié) | 大整數(shù) |
| FLOAT | 4字節(jié) | 單精度浮點數(shù) |
| DOUBLE | 8字節(jié) | 雙精度浮點整數(shù) |
| DECIMAL | ------ | DECIMAL(10,2),(不會丟失精度,涉及到錢等對精度要求高或者很重要的數(shù)據(jù)時用) |
- 為什么浮點數(shù)不精確,因為十進(jìn)制的浮點數(shù)轉(zhuǎn)成二進(jìn)制的浮點數(shù)會丟失精度
- decimal精確是因為不管保存整數(shù)還是浮點數(shù),都是采用字符串的方式來保存的。
DECIMAL(10,2)其中的10表示整數(shù)位和小數(shù)位加起來一共10個字符,2表示精確到小數(shù)點后兩位
2、字符串
| 類型 | 大小 | 說明 |
|---|---|---|
| CHAR | 1-255字符 | 固定長度字符串 |
| VARCHAR | 1-65535字符 | 不固定長度字符串 |
| TEXT | 1-65535字符 | 不確定長度字符串 |
| MEDIUMTEXT | 1-1千6百萬字符 | 不確定長度字符串 |
| LONGTEXT | 1-42億字符 | 不確定長度字符串 |
3、日期類型
| 類型 | 大小 | 說明 |
|---|---|---|
| DATE | 3字節(jié) | 日期 |
| TIME | 3字節(jié) | 時間 |
| YEAR | 1字節(jié) | 年份 |
| DATETIME | 8字節(jié) | 日期時間 |
| TIMESTAMP | 4字節(jié) | 時間戳 |
二、數(shù)據(jù)庫表的相關(guān)操作
邏輯空間對應(yīng)的是文件夾,數(shù)據(jù)表對應(yīng)的是文件夾中的
.ibd文件
1、定義邏輯空間
# 展示所有的邏輯空間
SHOW DATABASES;
# 創(chuàng)建邏輯空間
CREATE DATABASE demo;
# 刪除邏輯空間
DROP DATABASE demo;
# 使用(或者說切換到) demo 邏輯空間
USE demo;
2、定義數(shù)據(jù)表
# 創(chuàng)建 student 數(shù)據(jù)表
CREATE TABLE student (
id INT UNSIGNED PRIMARY KEY,
name VARCHAR(20) NOT NULL,
sex CHAR(1) NOT NULL,
birthday DATE NOT NULL,
tel CHAR(11) NOT NULL,
remark VARCHAR(200)
);
# 在數(shù)據(jù)表 student 中插入數(shù)據(jù)
INSERT INTO student VALUES(1, "李強(qiáng)", "男", "1990-05-06", "13355556666", NULL);
# 查看當(dāng)前邏輯空間下所有數(shù)據(jù)表名
SHOW TABLES;
# 查看數(shù)據(jù)表 student 的表結(jié)構(gòu)
DESC student;
# 查看數(shù)據(jù)表 student 創(chuàng)建時候的sql語句
SHOW CREATE TABLE student;
# 刪除數(shù)據(jù)表 student
DROP TABLE student;
3、修改數(shù)據(jù)表結(jié)構(gòu)
# 在數(shù)據(jù)表中添加新字段
ALTER TABLE student
ADD address VARCHAR(200) NOT NULL,
ADD home_tel CHAR(11) NOT NULL;
# 修改數(shù)據(jù)表中已經(jīng)存在的字段的數(shù)據(jù)類型和約束
ALTER TABLE student
MODIFY home_tel VARCHAR(20) NOT NULL;
# 修改數(shù)據(jù)表中的字段名
ALTER TABLE student
CHANGE address home_address VARCHAR(200) NOT NULL;
# 刪除數(shù)據(jù)表中已經(jīng)存在的字段
ALTER TABLE student
DROP home_address,
DROP home_tel;
4、字段約束
- MySQL中的字段約束共有四種
| 約束名稱 | 關(guān)鍵字 | 描述 |
|---|---|---|
| 主鍵約束 | PRIMARY KEY | 字段值唯一,且不能為NULL |
| 非空約束 | NOT NULL | 字段值不能為NULL |
| 唯一約束 | UNIQUE | 字段值唯一,且可以為NULL |
| 外鍵約束 | FOREIGN KEY | 保持關(guān)聯(lián)數(shù)據(jù)的邏輯性 |
# 創(chuàng)建部門表
CREATE TABLE t_dept(
deptno INT UNSIGNED PRIMARY KEY,
deptname VARCHAR(10) NOT NULL UNIQUE,
tel CHAR(11) UNIQUE
);
# 創(chuàng)建員工表,設(shè)置外鍵關(guān)聯(lián)部門表中的 deptno
CREATE TABLE t_emp (
empno INT UNSIGNED PRIMARY KEY,
empname VARCHAR(20) NOT NULL,
sex ENUM("男", "女") NOT NULL,
deptno INT UNSIGNED NOT NULL,
hiredate DATE NOT NULL,
FOREIGN KEY (deptno) REFERENCES t_dept(deptno)
);
5、數(shù)據(jù)表索引
- 數(shù)據(jù)量大,而且經(jīng)常被查詢的數(shù)據(jù)表可以設(shè)置索引
- 索引只添加在經(jīng)常被用作檢索條件的字段的上面
- 不要在大字段上創(chuàng)建索引(字符長度超過50的字符串)
# 創(chuàng)建數(shù)據(jù)表 t_message 并給 type字段 添加索引 idx_type
CREATE TABLE t_message (
id INT UNSIGNED PRIMARY KEY,
content VARCHAR(200) NOT NULL,
type ENUM("公告", "個人通知", "通報") NOT NULL,
create_time TIMESTAMP NOT NULL,
INDEX idx_type(type)
);
# 展示數(shù)據(jù)表 t_message 中的索引
SHOW INDEX FROM t_message;
# 刪除數(shù)據(jù)表中的索引
DROP INDEX idx_type ON t_message;
# 給數(shù)據(jù)表中的字段 type 添加索引(下面是兩種方法)
CREATE INDEX idx_type ON t_message(type);
ALTER TABLE t_message ADD INDEX idx_type(type);
三、數(shù)據(jù)庫表的基本查詢
1、普通查詢
# 查詢數(shù)據(jù)表中所有字段信息
SELECT * FROM t_emp;
# 查詢數(shù)據(jù)表中 empno, ename, sal 三個字段的信息
SELECT empno, ename, sal FROM t_emp;
# 使用列別名
# 通常情況下, SELECT子句中使用了表達(dá)式,那么這列的名字就默認(rèn)為表達(dá)式,因此可以通過 AS 來對結(jié)果集中列名進(jìn)行重命名
SELECT
empno,
sal * 12 AS "income"
FROM t_emp;
2、數(shù)據(jù)分頁
# 使用LIMIT關(guān)鍵字進(jìn)行數(shù)據(jù)分頁,
SELECT ... FROM ... LIMIT 起始位置, 偏移量;
# 例子
SELECT empno, ename FROM t_emp LIMIT 0, 5;
3、排序
# 在數(shù)據(jù)表t_emp中按字段 sal 進(jìn)行升序排序,默認(rèn)就是升序(ASC寫不寫都可)
SELECT empno,ename,sal,deptno
FROM t_emp
ORDER BY sal ASC;
# 在數(shù)據(jù)表t_emp中按字段 sal 進(jìn)行降序排序
SELECT empno,ename,sal,deptno
FROM t_emp
ORDER BY sal DESC;
# 單個字段排序,如果有兩條數(shù)據(jù),排序字段內(nèi)容相等,那么會根據(jù)這兩條數(shù)據(jù)的主鍵升序進(jìn)行排序
# 可以設(shè)置多個排序字段,第一個字段升序排列,第二個字段降序排列
SELECT deptno,ename,sal
FROM t_emp
ORDER BY deptno ASC, sal DESC;
# ORDER BY 和 LIMIT 混合使用,可以實現(xiàn)排序加分頁的效果
# 獲取員工工資排在前五位的員工數(shù)據(jù)
SELECT empno,ename,sal
FROM t_emp
ORDER BY sal DESC LIMIT 0, 5;
4、去除重復(fù)記錄
- 使用
DISTINCT的SELECT子句中只能查詢一列數(shù)據(jù),如果查詢多列,去除重復(fù)記錄就會失效 -
DISTINCT關(guān)鍵字只能在SELECT子句中使用一次
# 獲取員工表中所有職位
SELECT DISTINCT job FROM t_emp;
5、條件查詢
比較運(yùn)算符
| 序號 | 表達(dá)式 | 意義 | 例子 |
|---|---|---|---|
| 1 | > | 大于 | age > 18 |
| 2 | >= | 大于等于 | age >= 18 |
| 3 | < | 小于 | age < 18 |
| 4 | <= | 小于等于 | age <= 18 |
| 5 | = | 等于 | age = 18 |
| 6 | != | 不等于 | age != 18 |
| 7 | IN | 包含 | age IN(10,20,30) |
| 8 | IS NULL | 為空 | dept IS NULL |
| 9 | IS NOT NULL | 不為空 | dept IS NOT NULL |
| 10 | BETWEEN AND | 范圍 | sal BETWEEN 2000 AND 3000 |
| 11 | LIKE | 模糊查詢 | ename LIKE "A%" |
| 12 | REGEXP | 正則表達(dá)式 | ename REGEXP "[a-zA-Z]{4}" |
1、
LIKE "A%"中的%表示0到多個字符的意思,哪怕沒有字符也會匹配
2、LIKE "A%"表示以字符A開頭;LIKE "%A"表示以字符A結(jié)尾;LIKE "%A%"表示含有A這個字符,開頭結(jié)尾還是在中間都可以匹配,
/*
NULL 和其它數(shù)字做加減乘除運(yùn)算,結(jié)果都為 NULL,為了做計算的時候規(guī)避這種情況
引入IFNULL(expr1,expr2),expr1為要參與計算的參數(shù),exp2為當(dāng)expr1為NULL時候用什么值來參與運(yùn)算
*/
/*
函數(shù)DATEDIFF(expr1,expr2),可計算兩個時間之間的差值,expr1 減去 expr2,得到的結(jié)果為天數(shù)
函數(shù)NOW(),可以獲取當(dāng)前時間
*/
# 獲取員工表中部門編號為10,并且年收入超過15000,并且工齡超過20年的員工信息
SELECT empno,ename,sal,hiredate
FROM t_emp
WHERE deptno=10 AND ((sal+IFNULL(comm,0))*12 )>=15000
AND DATEDIFF(NOW(),hiredate)/365>=20;
# 獲取部門編號在10,20,30之間,并且入職日期在1985年之前,并且job不是SALESMAN的員工信息
SELECT empno,ename,deptno,hiredate,job
FROM t_emp
WHERE deptno IN(10,20,30) AND hiredate<"1985-01-01" AND job!="SALESMAN";
邏輯運(yùn)算符
| 序號 | 表達(dá)式 | 意義 | 例子 |
|---|---|---|---|
| 1 | AND | 與關(guān)系 | age > 18 AND sex = "男" |
| 2 | OR | 或關(guān)系 | age > 18 OR sex="男" |
| 3 | NOT | 非關(guān)系 | NOT deptno = 20 |
| 4 | XOR | 異或關(guān)系 | age > 18 XOR sex="男" |
SELECT ename,deptno,sal
FROM t_emp
WHERE NOT deptno IN(10, 20) XOR sal>=5000;
1、where子句中,條件執(zhí)行的順序是從左到右的。所以我們應(yīng)該把索引條件,或者篩選掉記錄最多的條件寫在最左側(cè),這樣會提高查詢速度
2、條件查詢中各種子句執(zhí)行順序是: FROM > WHERE > GROUP BY > SELECT > ORDER BY > LIMIT
四、數(shù)據(jù)庫表的高級查詢
1、聚合函數(shù)
| 序號 | 函數(shù)名 | 說明 |
|---|---|---|
| 1 | SUM | 求和,只能用于數(shù)字類型,日期類型統(tǒng)計結(jié)果是毫秒數(shù)相加,字符類型為0 |
| 2 | MAX | 獲得非空值的最大值 |
| 3 | MIN | 獲得非空值的最小值 |
| 4 | AVG | 獲得非空值的平均值,非數(shù)字?jǐn)?shù)據(jù)統(tǒng)計結(jié)果為0 |
| 5 | COUNT | COUNT(*)用于獲得包含空值的記錄數(shù),COUNT(列名)用于獲得包含非空值的記錄數(shù) |
2、分組查詢
默認(rèn)情況下匯總函數(shù)是對全表范圍內(nèi)的數(shù)據(jù)做統(tǒng)計。
GROUP BY子句的作用是通過一定的規(guī)則將一個數(shù)據(jù)集劃分成若干個小的區(qū)域,然后針對每個小區(qū)域分別進(jìn)行數(shù)據(jù)匯總處理。
# 查詢每個部門里,每種職位的人員數(shù)量和平均底薪,并按部門排序
SELECT deptno,job,COUNT(*),AVG(sal + IFNULL(comm,0))
FROM t_emp
GROUP BY deptno, job
ORDER BY deptno;
# GROUP_CONCAT()函數(shù)可以把分組查詢中的某個字段拼接成一個字符串
# 查詢每個部門內(nèi)底薪超過2000元的人數(shù)和員工姓名
SELECT deptno,GROUP_CONCAT(ename),COUNT(*)
FROM t_emp
WHERE sal>=2000
GROUP BY deptno;
1、查詢語句中如果含有
GROUP BY子句,那么SELECT子句中的內(nèi)容就必須要遵守規(guī)定:SELECT子句中可以包括聚合函數(shù),或者GROUP BY子句的分組列,其余內(nèi)容均不可以出現(xiàn)在SELECT子句中
2、GROUP_CONCAT函數(shù)可以把分組查詢中的某個字段拼接成一個字符串,中間用逗號分隔
# sal不應(yīng)該出現(xiàn)在SELECT子句中,以下語句執(zhí)行會直接報錯
SELECT deptno, COUNT(*), AVG(sal), sal
FROM t_emp GROUP BY deptno;
# 直接寫ename會報語法錯誤,使用GROUP_CONCAT可以避免語法錯誤,上面的sal也一樣
SELECT deptno, COUNT(*), GROUP_CONCAT(ename)
FROM t_emp
WHERE sal>=2000
GROUP BY deptno;
WITH ROLLUP對分組結(jié)果集再次做匯總計算
# 對分組結(jié)果集再次做匯總計算
SELECT deptno, COUNT(*), AVG(sal), SUM(sal), MAX(sal), MIN(sal)
FROM t_emp
GROUP BY deptno WITH ROLLUP;
聚合函數(shù)作為查詢條件,需要引入
HAVING子句,HAVING子句不能獨(dú)立存在,必須依賴于GROUP BY子句
# 查詢每個部門中,1982年以后入職的員工超過2個人的部門編號
SELECT deptno
FROM t_emp
WHERE hiredate>"1982-01-01"
GROUP BY deptno HAVING COUNT(*)>=2
ORDER BY deptno ASC;
3、表連接查詢
表連接分為兩種:
內(nèi)連接和外連接
內(nèi)連接是結(jié)果集中只保留符合條件的記錄
外連接是不管符不符合連接條件,記錄都要保留在結(jié)果集中
1.內(nèi)連接
內(nèi)連接的多種語法形式
# JOIN 表連接關(guān)鍵字,ON 表連接條件
# 查詢每名員工的部門信息,下面三種寫法一樣
SELECT e.empno,e.ename,d.dname
FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno;
SELECT e.empno,e.ename,d.dname
FROM t_emp e JOIN t_dept d WHERE e.deptno=d.deptno;
SELECT e.empno,e.ename,d.dname
FROM t_emp e,t_dept d WHERE e.deptno=d.deptno;
內(nèi)連接的數(shù)據(jù)表不一定必須有同名字段,只要字段之間符合邏輯關(guān)系就可以
# 查詢每個員工的編號,姓名,部門名稱,底薪,職位,工資等級
SELECT e.empno,e.ename,d.dname,sal,job,s.grade
FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno
JOIN t_salgrade s ON e.sal BETWEEN s.losal AND s.hisal;
同一張數(shù)據(jù)表也可以做表連接
# 查詢與SCOTT相同部門的員工都有誰
#(1)符合邏輯習(xí)慣,但執(zhí)行效率低
SELECT ename
FROM t_emp
WHERE deptno=(SELECT deptno FROM t_emp WHERE ename="SCOTT") AND ename!="SCOTT";
#(2)利用表連接,執(zhí)行效率遠(yuǎn)高于(1)
# 相同數(shù)據(jù)表也可以做表連接
SELECT e2.ename
FROM t_emp e1 JOIN t_emp e2 ON e1.deptno=e2.deptno
WHERE e1.ename="SCOTT" AND e2.ename!="SCOTT";
查詢結(jié)果集也可以當(dāng)做一張表和其它表進(jìn)行連接
# 查詢底薪超過公司平均底薪的員工信息
# (1) 這種方法存在語法錯誤,ON相當(dāng)于WHERE篩選條件,不可用沒有明確值的聚合函數(shù)
SELECT e1.empno,e1.ename
FROM t_emp e1 JOIN t_emp e2 ON e1.sal>AVG(e2.sal);
#(2)將查詢結(jié)果集也當(dāng)做一張表和其它表進(jìn)行連接
SELECT e.ename,e.sal
FROM t_emp e JOIN (SELECT AVG(sal) AS avg FROM t_emp) t ON e.sal>t.avg;
# 查詢 RESEARCH 部門的人數(shù)、最高底薪、最低底薪、平均底薪、平均工齡
SELECT COUNT(*),MAX(e.sal),MIN(e.sal),AVG(e.sal),AVG(DATEDIFF(NOW(),e.hiredate))
FROM t_emp e JOIN t_dept d
WHERE d.dname="RESEARCH";
#查詢每種職業(yè)的最高工資、最低工資、平均工資、最高工資等級和最低工資等級
SELECT
e.job,
MAX(e.sal+IFNULL(e.comm,0)),
MIN(e.sal+IFNULL(e.comm,0)),
AVG(e.sal+IFNULL(e.comm,0)),
MAX(s.grade),
MIN(s.grade)
FROM t_emp e JOIN t_salgrade s
ON (e.sal+IFNULL(e.comm,0)) BETWEEN s.losal AND s.hisal
GROUP BY e.job;
# 查詢每個底薪超過部門平均底薪的員工信息
SELECT e1.deptno,e1.empno,e1.ename,e1.sal,e1.comm
FROM t_emp e1 JOIN (SELECT deptno, AVG(sal) AS avg FROM t_emp GROUP BY deptno) e2
ON e1.deptno=e2.deptno AND e1.sal>e2.avg;
2.外連接
1、外連接和內(nèi)連接的區(qū)別在于,除了符合條件的記錄之外,結(jié)果集中還會保留不符合條件的記錄。
2、左外連接就是保留左表的所有記錄,與右表做連接。如果右表有符合條件的記錄就與左表連接。如果右表沒有符合條件的記錄,就用NULL與左表連接。右外連接也是如此。
SELECT e.ename, e.deptno
FROM t_emp e
LEFT JOIN t_dept d
ON e.deptno=d.deptno;
UNION關(guān)鍵字可以將多個查詢語句的結(jié)果集進(jìn)行合并
# 查詢每個部門的名稱和部門的人數(shù)
SELECT d.dname, COUNT(e.deptno)
FROM t_emp e RIGHT JOIN t_dept d ON e.deptno=d.deptno
GROUP BY d.deptno;
# 查詢每個部門的名稱和部門的人數(shù),如果沒有部門的員工,部門名稱用NULL代替
(
SELECT d.dname, COUNT(e.deptno)
FROM t_emp e RIGHT JOIN t_dept d ON e.deptno=d.deptno
GROUP BY d.deptno
)
UNION
(
SELECT d.dname, COUNT(*)
FROM t_emp e LEFT JOIN t_dept d ON e.deptno=d.deptno
GROUP BY d.deptno
);
# 查詢每名員工的編號、姓名、部門、月薪、工資等級、工齡、上司編號、上司姓名、上司部門
SELECT e.empno, e.ename, d.dname,
e.sal+IFNULL(e.comm,0),
s.grade, FLOOR(DATEDIFF(NOW(),e.hiredate)/365),
t.empno as mempno, t.ename as mename, t.dname as mdname
FROM t_emp e LEFT JOIN t_dept d ON e.deptno=d.deptno
LEFT JOIN t_salgrade s ON e.sal BETWEEN s.losal AND s.hisal
LEFT JOIN
(SELECT e1.empno, e1.ename, d1.dname
FROM t_emp e1 JOIN t_dept d1 ON e1.deptno=d1.deptno) t
ON e.mgr=t.empno;
內(nèi)連接只保留符合條件的記錄,所以查詢條件寫在
ON子句和WHERE子句中的效果是相同的。但是外連接里,條件寫在WHERE子句里,不符合條件的記錄是會被過濾掉的,而不是保留下來。
# ON 不過濾
SELECT e.empno, e.ename, d.dname
FROM t_emp e LEFT JOIN t_dept d ON e.deptno = d.deptno
AND e.deptno = 10;
# WHERE 過濾
SELECT e.empno, e.ename, d.dname
FROM t_emp e LEFT JOIN t_dept d ON e.deptno = d.deptno
WHERE e.deptno = 10;
五、MySQL對數(shù)據(jù)的基本操作
1、INSERT語句
1、插入一條數(shù)據(jù)
INSERT INTO 表名(字段1, 字段2, ...) VALUES(值1, 值2, ...);
2、插入兩條數(shù)據(jù),多條就繼續(xù)添加
INSERT INTO 表名(字段1, 字段2, ...) VALUES(值1, 值2, ...), (值1, 值2, ...);
注:表名后面字段聲明不寫也可以執(zhí)行,但是執(zhí)行速度會受影響,因為MySQL在執(zhí)行sql語句的時候會做詞法分析,如果發(fā)現(xiàn)表名后面沒有寫字段聲明,會去查詢表結(jié)構(gòu),然后自動補(bǔ)上字段聲明,這樣的話,MySQL就不能立即執(zhí)行,需要做額外的工作,然后才會去執(zhí)行sql語句,往數(shù)據(jù)庫寫入數(shù)據(jù)。
所以,請務(wù)必在表名后寫字段聲明
# 向技術(shù)部添加一條員工記錄
INSERT INTO t_emp(empno, ename, job, mgr, hiredate, sal, comm, deptno)
VALUES(8001, "lily", "SALESMAN", 8000, "1990-01-02", 2000, NULL, (SELECT deptno FROM t_dept WHERE dname="技術(shù)部"));
IGNORE關(guān)鍵字會讓INSERT只插入數(shù)據(jù)庫不存在沖突的記錄
INSERT IGNORE INTO 表名....;
2、UPDATE語句
UPDATE 語句用于修改表的記錄,[]中可寫可不寫
UPDATE [IGNORE] 表名
SET 字段1=值1, 字段2=值2, ...
[WHERE 條件1...]
[ORDER BY ...]
[LIMIT ...]
# 把每個員工的編號和上司的編號+1,用 ORDER BY 子句完成
UPDATE t_emp SET empno=empno+1, mgr=mgr+1 ORDER BY empno DESC;
# 把月收入前三名的員工底薪減100元,用 LIMIT 子句完成
UPDATE t_emp SET sal=sal-100 ORDER BY sal DESC LIMIT 3;
# 把10部門中,工齡超過20年的員工,底薪增加200
UPDATE t_emp SET sal=sal+200 WHERE DATEDIFF(NOW(),hiredate)/365>20 AND deptno=10;
因為相關(guān)子查詢的效率非常低,所以我們可以利用表連接的方式來改造UPDATE語句
UPDATE 表1 JOIN 表2 ON 條件 SET 字段1=值1, 字段2=值2, ...
UPDATE 表1, 表2 SET 字段1=值1, 字段2=值2, ... WHERE 條件
# 把ALLEN調(diào)往RESEARCH部門,職務(wù)調(diào)整為ANALYST
# 方法1:利用子查詢,這種在SET中的子查詢是相關(guān)子查詢,改變一條數(shù)據(jù)還可以使用,但是同時改變多條數(shù)據(jù)的時候,效率會很低
UPDATE t_emp SET job="ANALYST", deptno=(SELECT deptno FROM t_dept WHERE dname="RESEARCH") WHERE ename="ALLEN";
# 方法2:利用表連接,JOIN可以寫成, 推薦
UPDATE t_emp e JOIN t_dept d SET e.job="ANALYST", e.deptno=d.deptno WHERE e.ename="ALLEN" AND d.dname="RESEARCH";
UPDATE t_emp e, t_dept d SET e.job="ANALYST", e.deptno=d.deptno WHERE e.ename="ALLEN" AND d.dname="RESEARCH";
# 把底薪低于公司平均底薪的員工,底薪增加150元,下面兩種寫法一樣
UPDATE t_emp e JOIN (SELECT AVG(sal) AS avg FROM t_emp) t SET e.sal=e.sal+150 WHERE e.sal<t.avg;
UPDATE t_emp e JOIN (SELECT AVG(sal) AS avg FROM t_emp) t ON e.sal<t.avg SET e.sal=e.sal+150;
UPDATE語句的表連接可以是內(nèi)連接,又可以是外連接
UPDATE 表1 [LEFT | RIGHT] JOIN 表2 ON 條件 SET 字段1=值1, 字段2=值2, ...
# 把沒有部門的員工,或者SALES部門低于2000元底薪的員工,都調(diào)往20部門
UPDATE t_emp e LEFT JOIN t_dept d ON e.deptno=d.deptno
SET e.deptno=20
WHERE e.deptno IS NULL OR (d.dname="SALES" AND e.sal<2000);
3、DELETE語句
DELETE 語句用于刪除記錄,[]中可寫可不寫
DELETE [IGNORE] FROM 表名
[WHERE 條件, 條件2, ...]
[ORDER BY ...]
[LIMIT ...]
# 刪除10部門中,工齡超過20年的員工記錄
DELETE FROM t_emp WHERE deptno=10 AND DATEDIFF(NOW(),hiredate)/365>20;
# 刪除20部門中工資最高的員工記錄
DELETE FROM t_emp WHERE deptno=20 ORDER BY sal+IFNULL(comm,0) DESC LIMIT 1;
因為相關(guān)子查詢效率非常低,所以我們可以用表連接的方式來改造DELETE語句
DELETE 表1, ... FROM 表1 JOIN 表2 ON 條件
WHERE 條件1, 條件2, ...
ORDER BY ...
LIMIT ...
# 刪除SALES部門和該部門的全部員工記錄
DELETE e, d
FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno
WHERE d.dname="SALES";
# 刪除每個低于部門平均底薪的員工記錄
DELETE e
FROM t_emp e JOIN (SELECT deptno, AVG(sal) AS avg FROM t_emp GROUP BY deptno) t
ON e.deptno=t.deptno AND e.sal<t.avg;
# 刪除員工KING和他的直接下屬的員工記錄,用表連接實現(xiàn)
DELETE e
FROM t_emp e JOIN
(SELECT empno FROM t_emp WHERE ename="KING") t
ON e.mgr=t.empno OR e.empno=t.empno;
DELETE語句的表連接既可以是內(nèi)連接,又可以是外連接
DELETE 表1, ... FROM 表1 [LEFT | RIGHT] JOIN 表2 ON 條件...
# 刪除SALES部門的員工,以及沒有部門的員工,下面兩種方法都可,推薦第二種
DELETE e
FROM t_emp e JOIN (SELECT deptno FROM t_dept WHERE dname="SALES") t
ON e.deptno=t.deptno OR e.deptno IS NULL;
DELETE e
FROM t_emp e LEFT JOIN t_dept d ON e.deptno=d.deptno
WHERE d.dname="SALES" OR e.deptno IS NULL;
快速刪除數(shù)據(jù)表全部記錄
1、DELETE語句是在事務(wù)機(jī)制下刪除記錄,刪除記錄之前,先把將要刪除的記錄保存到日志文件里,然后再刪除記錄
2、TRUNCATE語句在事務(wù)機(jī)制之外刪除記錄,速度遠(yuǎn)超過DELETE語句
3、語法如下:
TRUNCATE TABLE 表名;
# 刪除員工表中的所有數(shù)據(jù)
TRUNCATE TABLE t_emp;
六、MySQL基本函數(shù)的使用
1、數(shù)字函數(shù)
| 函數(shù) | 功能 | 用例 |
|---|---|---|
| ABS | 絕對值 | ABS(-100) |
| ROUND | 四舍五入 | ROUND(4.62) |
| FLOOR | 強(qiáng)制舍位到最近的整數(shù) | FLOOR(9.9) |
| CEIL | 強(qiáng)制進(jìn)位到最近的整數(shù) | CEIL(3.2) |
| POWER | 冪函數(shù) | POWER(2,3) |
| LOG | 對數(shù)函數(shù) | LOG(7,3) |
| LN | 對數(shù)函數(shù) | LN(10) |
ROUND():四舍五入
CEIL():進(jìn)位
FLOOR():舍位
# 四舍五入
SELECT ROUND(1.4); // 1
SELECT ROUND(1.5); // 2
# 進(jìn)位
SELECT CEIL(1.1); // 2
# 舍位
SELECT FLOOR(1.9); // 1
| 函數(shù) | 功能 | 用例 |
|---|---|---|
| SQRT | 開平方 | SQRT(9) |
| PI | 圓周率 | PI() |
| SIN | 三角函數(shù) | SIN(1) |
| COS | 三角函數(shù) | COS(1) |
| TAN | 三角函數(shù) | TAN(1) |
| COT | 三角函數(shù) | COT(1) |
| PADIANS | 角度轉(zhuǎn)換弧度 | PADIANS(30) |
| DEGREES | 弧度轉(zhuǎn)換角度 | DEGREES(1) |
2、字符函數(shù)
| 函數(shù) | 功能 | 用例 |
|---|---|---|
| LOWER | 轉(zhuǎn)換小寫字符 | LOWER(ename) |
| UPPER | 轉(zhuǎn)換大寫字符 | UPPER(ename) |
| LENGTH | 字符數(shù)量 | LENGTH(ename) |
| CONCAT | 連接字符串 | CONCAT(sal, "$") |
| INSTR | 字符出現(xiàn)的位置 | INSTR(ename, "A") |
| INSERT | 插入/替換字符 | INSERT("你好", 1, 0, "先生") |
| REPLACE | 替換字符 | REPLACE("你好先生", "先生", "女士") |
| 函數(shù) | 功能 | 用例 |
|---|---|---|
| SUBSTR | 截取字符串 | SUBSTR("你好世界", 3, 4) |
| SUBSTRING | 截取字符串 | SUBSTRING("你好世界", 3, 2) |
| LPAD | 左側(cè)填充字符 | LPAD("Hello", 10, "*") |
| RPAD | 右側(cè)填充字符 | RPAD("Hello", 10, "*") |
| TRIM | 去除首尾空格 | TRIM(" 你好世界 ") |
3、日期函數(shù)
| 函數(shù) | 功能 | 格式 |
|---|---|---|
| NOW() | 獲得系統(tǒng)日期和時間 | yyyy-MM-dd hh:mm:ss |
| CURDATE() | 獲取當(dāng)前系統(tǒng)日期 | yyyy-MM-dd |
| CURTIME() | 獲取當(dāng)前系統(tǒng)時間 | hh:mm:ss |
DATE_FORMAT()函數(shù)用于格式化日期,返回用戶想要的日期格式
DATE_FORMAT(date,format)
date:日期,format:表達(dá)式
# 獲取員工姓名和入職年份
SELECT ename, DATE_FORMAT(hiredate,"%Y") FROM t_emp;
| 占位符 | 作用 | 占位符 | 作用 |
|---|---|---|---|
| %Y | 年份 | %m | 月份 |
| %d | 日期 | %w | 星期(數(shù)字) |
| %W | 星期(名稱) | %j | 本年第幾天 |
| %U | 本年第幾周 | %H | 小時(24) |
| %h | 小時(12) | %i | 分鐘 |
| %s | 秒 | %r | 時間(12) |
| %T | 時間(24) |
# 利用日期函數(shù),查詢明年你的生日是星期幾
SELECT DATE_FORMAT("2023-11-13","%w"); // 0代表周天
SELECT DATE_FORMAT("2023-11-13","%W");
# 利用日期函數(shù),查詢1981年上半年入職的員工有多少人
SELECT ename, hiredate FROM t_emp
WHERE (DATE_FORMAT(hiredate,"%Y") = 1981) AND DATE_FORMAT(hiredate,"%m") < 7;
MySQL數(shù)據(jù)庫里面,兩個日期不能直接加減,日期也不能與數(shù)字加減
DATE_ADD()函數(shù)可以實現(xiàn)日期的偏移計算,而且時間單位很靈活
DATE_ADD(日期,INTERVAL 偏移量 時間單位)
# 15天之后的時間
SELECT DATE_ADD(NOW(),INTERVAL 15 DAY);
# 300分鐘之前的時間
SELECT DATE_ADD(NOW(),INTERVAL -300 MINUTE);
# 6個月零3天之前的時間
SELECT DATE_ADD(DATE_ADD(NOW(),INTERVAL -6 M ONTH),INTERVAL -3 DAY);
計算日期之間相隔的天數(shù)
DATEDIFF()函數(shù)用來計算兩個日期之間相差的天數(shù)
DATEDIFF(日期,日期)
4、條件函數(shù)
SQL語句中可以利用條件函數(shù)來實現(xiàn)編程語言里的條件判斷
IFNULL(表達(dá)式, 值)
IF(表達(dá)式, 值1, 值2)
# 中秋節(jié)公司發(fā)放禮品,SALES部門發(fā)放禮品A,其余部門發(fā)放禮品B,打印每名員工獲得的禮品
SELECT e.ename, d.deptno, d.dname, IF(d.dname="SALES","A","B")
FROM t_emp e JOIN t_dept d
WHERE e.deptno=d.deptno;
復(fù)雜的條件判斷可以用條件語句來實現(xiàn),比IF語句更強(qiáng)大
CASE
WHERE 表達(dá)式 THEN 值1
WHERE 表達(dá)式 THEN 值2
......
ELSE 值N
END
# 公司年慶決定組織員工集體旅游,每個部門旅游目的地是不同的。SALES部門去P1地點,ACCOUNTING部門去P2地點,RESEARCH部門去P3地點,查詢每名員工的旅行地點。
SELECT
e.ename,
CASE
WHEN d.dname="SALES" THEN "P1"
WHEN d.dname="ACCOUNTING" THEN "P2"
WHEN d.dname="RESEARCH" THEN "P3"
END AS PLACE
FROM t_emp e JOIN t_dept d
WHERE e.deptno=d.deptno;
# 公司決定為員工調(diào)整基本工資,具體調(diào)整方案如下
# 1、SALES部門中工齡超過20年,漲幅10%
# 2、SALES部門中工齡不滿20年,漲幅5%
# 3、ACCOUNTING部門, +300元
# 4、RESEARCH部門里低于部門平均底薪, +200元
# 5、沒有部門的員工, +100元
UPDATE t_emp e LEFT JOIN t_dept d ON e.deptno=d.deptno
LEFT JOIN (SELECT deptno, AVG(sal) AS avg FROM t_emp GROUP BY deptno) t ON e.deptno=t.deptno
SET e.sal=(
CASE
WHEN d.dname="SALES" AND DATEDIFF(NOW(),e.hiredate)/365>20 THEN e.sal*1.1
WHEN d.dname="SALES" AND DATEDIFF(NOW(),e.hiredate)<20 THEN e.sal*1.05
WHEN d.dname="ACCOUNTING" THEN e.sal+300
WHEN d.dname="RESEARCH" AND e.sal<t.avg THEN e.sal+200
WHEN d.dname IS NULL THEN e.sal+100
ELSE e.sal
END
);