1 數據約束
1.1 簡介
給表添加數據約束,從而約束用戶操作表數據的行爲。
1.2 默認值約束
注意: 當前沒有插入默認值字段的時候,默認值纔會起作用
– 1.1 默認值(default)
CREATE TABLE test(
NAME VARCHAR(20),
gender VARCHAR(2) DEFAULT '男'
)
INSERT INTO test(NAME) VALUES('張三');
INSERT INTO test(NAME,gender) VALUES('張三',NULL);
SELECT * FROM test;
– 需求:當不插入gender的時候,分配一個‘男’的默認值
– 注意: 1)當沒有插入gender字段的時候,分配一個默認值
1.3 非空約束
– 1.2 非空(not null)
CREATE TABLE test(
NAME VARCHAR(20) NOT NULL,
gender VARCHAR(2)
)
– 需求: name字段一定要有值(不能不插入數據,不能是null),這是給name添加非空約束
– 1)非空約束,不能不插入值
INSERT INTO test(gender) VALUES(‘男’); – ERROR 1364 (HY000):
Field ‘NAME’ doesn’t have a default value
– 2)非空約束,不能插入null
INSERT INTO test(NAME,gender) VALUES(NULL,’男’);
– ERROR 1048 (23000): Column ‘NAME’ cannot be null
1.4 唯一約束
CREATE TABLE test(
id INT UNIQUE,
NAME VARCHAR(20)
)
– 需求: id的值不能出現重複值。這時就要給id添加一個唯一約束。
INSERT INTO test(id,NAME) VALUES(1,’張三’);
– 1)不能插入重複的值
INSERT INTO test(id,NAME) VALUES(1,’李四’); – Duplicate entry ‘1’ for key ‘id’
INSERT INTO test(id,NAME) VALUES(2,’李四’);
– 2)唯一約束,可以插入多個null。所以唯一約束不能約束null
INSERT INTO test(id,NAME) VALUES(NULL,’王五’);
INSERT INTO test(id,NAME) VALUES(NULL,’陳六’);
1.5 主鍵約束
– 1.4 主鍵約束(primary key)(唯一+非空)
– 注意:
– 1)通常情況下,我們會給每張表都會設置一個主鍵字段,用來標記記錄的唯一性
– 2)但是不建議把業務含義字段作爲主鍵,因爲隨着業務的變化,業務字段可能會出現重複。
– 3)建議給每張張獨立添加一個叫id的字段,把這個id字段設置成主鍵,用來作爲記錄的唯一性。
– 創建表給id字段施加主鍵
CREATE TABLE test(
id INT PRIMARY KEY,
NAME VARCHAR(20)
)
– 1)唯一性
INSERT INTO test(id,NAME) VALUES(1,’張三’);
INSERT INTO test(id,NAME) VALUES(1,’張三’); – Duplicate entry ‘1’ for key ‘PRIMARY’
– 2)非空性
INSERT INTO test(id,NAME) VALUES(NULL,’張三’); – ERROR 1048 (23000): Column ‘id’ cannot be null
1.6 自增長約束(auto_increment)
– 1.5 自增長約束(auto_increment)
– 創建表給id字段添加主鍵自增長約束
CREATE TABLE test(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
)
– 自增長約束:初始值爲0,每次遞增1
– 需求:id的值不需要我們開發者管理,交給數據庫維護,這時給id添加自增長約束。
INSERT INTO test(NAME) VALUES(‘張三’);
INSERT INTO test(NAME) VALUES(‘李四’);
INSERT INTO test(NAME) VALUES(‘王五’);
– 刪除數據
– delete from test where id=2;
– 使用truncate table刪除數據的時候,可以把自增長的初始值置爲0
TRUNCATE TABLE test;
SELECT * FROM test;
1.7 外鍵約束
外鍵約束: 約束兩種表的情況
問題:什麼情況下會出現兩種表?
答案:員工表中出現部門名稱的冗餘字段!!!!
如何解決部門名稱冗餘問題?
答案:獨立設計一張部門表,把部門名稱放到部門表中,這是員工表只需要關聯部門的id即可!!
問題: 當插入員工表的部門id的時候,可能會出現不存在的部門id!!這是非法數據!!!如何防止非法數據的插入?
答案: 這是可以把員工表的部門id設置爲外鍵約束。
當有了外鍵約束之後,操作數據的順序如下:
插入數據: 先插入主表的數據,再插入副表數據
修改數據: 先修改主表數據,再修改副表數據
刪除數據: 先刪除副表數據,再刪除主表數據
– 1.6 外鍵約束
– 外鍵作用: 約束兩種表的數據
– 問題: 約束哪種情況下的兩種表呢?
– 員工表
CREATE TABLE employee(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
deptName VARCHAR(20)
)
INSERT INTO employee(NAME,deptName) VALUES(‘張三’,’軟件開發部’);
INSERT INTO employee(NAME,deptName) VALUES(‘李四’,’軟件維護部’);
INSERT INTO employee(NAME,deptName) VALUES(‘王五’,’軟件開發部’);
INSERT INTO employee(NAME,deptName) VALUES(‘陳六’,’軟件開發部’);
– 問題:每次插入員工數據時,部門名稱數據會出現重複(冗餘),如果數據出現冗餘,那麼會浪費數據庫存儲空間。
– 如何解決部門名稱數據冗餘的問題? 這時就可以設計一張獨立的 部門表,把部門名稱放到部門表中。
– 員工表
CREATE TABLE employee(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
deptId INT
)
– 部門表
CREATE TABLE dept(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
)
SELECT * FROM employee;
SELECT * FROM dept;
INSERT INTO dept(NAME) VALUES(‘軟件開發部’);
INSERT INTO dept(NAME) VALUES(‘軟件維護部’);
INSERT INTO employee(NAME,deptId) VALUES(‘陳六’,1);
INSERT INTO employee(NAME,deptId) VALUES(‘王五’,1);
INSERT INTO employee(NAME,deptId) VALUES(‘張三’,3); – 問題:在插入員工表的部門id的時候,插入了不存在的部門id,如何防止這種非法數據的插入,這時就添加外鍵約束了。
– 添加外鍵約束(foreign key)
– 需求:deptId字段值來自於dept表的id字段的值,這時可以給deptId字段添加外鍵約束。
– 員工表(副表: 被別的表約束。外鍵設置在副表)
CREATE TABLE employee(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
deptId INT,
CONSTRAINT employee_dept_fk FOREIGN KEY(deptId) REFERENCES dept(id)
-- 外鍵名稱 外鍵字段 參考
)
– 部門表(主表:約束別人的表)
CREATE TABLE dept(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
)
SELECT * FROM employee;
SELECT * FROM dept;
INSERT INTO employee(NAME,deptId) VALUES(‘陳六’,1);
INSERT INTO employee(NAME,deptId) VALUES(‘王五’,1);
– 插入數據
INSERT INTO employee(NAME,deptId) VALUES(‘張三’,3); – 違反外鍵約束:a foreign key constraint fails
– 修改數據
UPDATE employee SET deptId=5 WHERE id=2; – a foreign key constraint fails
– 刪除數據
DELETE FROM dept WHERE id=1; – a foreign key constraint fails
– 外鍵約束在什麼情況下,會其作用?
– 插入數據:當往副表插入了主表不存在的數據時,外鍵起作用
– 修改數據:當往副表修改爲主表不存在的數據時,外鍵起作用
– 刪除數據: 副表中有關聯主表的數據的時候,當刪除主表數據,外鍵其作用
– 當有了外鍵之後,應該如何管理數據呢?
– 插入數據: 先插入主表的數據,再插入副表數據
– 修改數據: 先修改主表數據,再修改副表數據
UPDATE employee SET deptId=3 WHERE id=5;
UPDATE dept SET id=3 WHERE id=2;
– 刪除數據:先刪除副表數據,再刪除主表數據
DELETE FROM dept WHERE id=3;
DELETE FROM employee WHERE deptId=3;
1.8 級聯技術
級聯: 當有了外鍵的時候,我們希望修改或刪除數據的時候,修改或刪除了主表的數據,同時能夠影響副表的數據,這時就可以使用級聯。
CREATE TABLE employee(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
deptId INT,
-- 添加級聯修改: ON UPDATE CASCADE
-- 添加級聯刪除: ON DELETE CASCADE
CONSTRAINT employee_dept_fk FOREIGN KEY(deptId) REFERENCES dept(id) ON UPDATE CASCADE ON DELETE CASCADE
-- 外鍵名稱 外鍵字段 參考
)
2 數據庫設計
2.1 引入
需求分析: 原始需求 -> 業務需求
客戶 業務模型:客戶(姓名 登記時間 郵箱 微信號 )
需求設計:
業務模型(客戶業務模型): -》 抽取實體模型: class Customer{name email weixin}
業務模型(客戶業務模型) -> 數據模型:設計數據庫表(customer表: 字段)
2.2 數據庫設計的三大範式
第一範式: 要求表的每個字段必須獨立的不可分割的單元
學生表: student name --違反第一範式
張三|狗娃
王含|張小含
查詢: 現用名中包含‘張’的學生
select * from student where name like '%張%';
學生表: student name old_name --符合第一範式
張三 狗娃
王含 張小含
第二範式: 在第一範式的基礎上,要求表的除主鍵以外的字段都和主鍵有依賴關係的。
一張表應該只表達一個意思!!!!
員工表:employee
員工編號 員工姓名 部門名稱 訂單名稱 --違反第二範式
員工表:employee
員工編號 員工姓名 部門名稱 --符合第二範式
訂單表:
訂單編號 訂單名稱
第三範式: 在第二範式基礎上,要求表的除主鍵外的字段都只能和主鍵有直接決定的依賴關係。
員工表:employee --不符合第三範式(出現數據冗餘)
員工編號 員工姓名 部門編號 部門名稱
1 張三 1 軟件開發部
2 李四 1 軟件開發部
員工表:employee --符合第三範式(降低數據冗餘)
員工編號 員工姓名 部門編號
1 張三 1
2 李四 1
部門表: dept
部門編號 部門名稱
1 軟件開發部
數據庫存儲空間 和 數據查詢效率
3 多表查詢
– 1.1 交叉連接查詢(笛卡爾乘積: 4*3=12,產生笛卡爾積的原因是沒有足夠的連接條件)
– 需求: 員工及其部門
SELECT employee.name,dept.name FROM employee,dept;
– 多表查詢的步驟: 1)確定查詢哪些表 2)確定查詢哪些字段 3)確定連接條件(規則: 表數量-1)
– 內連接效果:只有滿足連接條件的數據纔會顯示出來
– 1.2 內連接查詢(使用最多)
SELECT e.name,d.name
FROM employee e,dept d
WHERE e.deptId=d.id;
– 另一種語法
SELECT e.name,d.name
FROM employee e
INNER JOIN dept d
ON e.deptId=d.id;
– 1.3 左外連接查詢(其次)
– 需求: 查詢部門及其部門的員工(部門全部顯示)
– 左外連接查詢效果: 左表(部門表)的數據全部顯示,右表(員工)的數據當滿足連接條件的時候,
– 就顯示滿足條件的的數據,但是如果不滿足連接條件,則顯示null
– 預期結果:
– 軟件開發部 張三
– 軟件開發部 王五
– 軟件維護部 李四
– 軟件維護部 陳六
– 祕書部 null
SELECT d.name,e.name
FROM dept d
LEFT OUTER JOIN employee e
ON d.id=e.deptId;
– 1.4 右外連接查詢
– 右外連接查詢效果: 右表(部門表)的數據全部顯示,左表(員工)的數據當滿足連接條件的時候,
– 就顯示滿足條件的數據,但是如果不滿足連接條件,則顯示null
SELECT d.name,e.name
FROM employee e
RIGHT OUTER JOIN dept d
ON d.id=e.deptId;
– 1.5 自連接查詢
– 需求: 查詢員工姓名及其上司姓名(沒有上司的員工也顯示)
– 預期結果:
員工 上司
– 張三 null
– 李四 張三
– 王五 李四
– 陳六 王五
SELECT e.name AS '員工',b.name AS '上司'
FROM employee e
LEFT OUTER JOIN employee b
ON e.bossId=b.id;
4 mysql存儲過程
4.1 引入
存儲過程,其實就是帶邏輯的(多個)sql語句。也是sql編程。
4.2 存儲過程的特點
1)存儲過程保存到數據庫服務器端,通過數據庫客戶端工具調用存儲過程
2)存儲過程的效率會非常高!因爲存儲過程是在數據庫服務器端執行。
3)存儲過程的移植性非常差的!
4.3 存儲過程語法
創建存儲過程
– 定義結束符號
DELIMITER 結束符號
CREATE PROCEDURE 存儲過程名稱 (形式參數列表)
BEGIN
多個sql語句
END 結束符號
– 調用存儲過程
CALL 存儲過程名稱(實際參數列表);
參數類型:
IN: 輸入參數,可以攜帶數據到存儲過程中
OUT: 輸出參數,可以攜帶數據到存儲過程外面。
INOUT: 輸入輸出參數。
– 3.1 帶有輸入參數的存儲過程
– 需求: 傳入員工id查詢對應的員工
DELIMITER $
CREATE PROCEDURE pro_testByIn(IN eid INT) -- 參數類型(IN) 參數名稱 數據類型(int)
BEGIN
SELECT * FROM employee WHERE id=eid;
END $
– 調用
CALL pro_testByIn(2);
– 3.2 帶有輸出參數的存儲過程
DELIMITER $
CREATE PROCEDURE pro_testByOut(OUT n VARCHAR(20))
BEGIN
-- 修改變量n
SET n = '輸出參數';
END $
– 問題: 如何接收存儲過程的輸出參數???
– 定義變量去接收輸出參數數據。
– mysql數據庫三種變量:
– 1)全局變量。mysql內置的變量,mysql程序關閉的時候全局變量纔會失效!!
– show variables:產看全局變量
– character_set_client: mysql接收的客戶端的數據編碼
– character_set_results: mysql使用什麼編碼輸出給客戶端數據
– 查看某個全局變量: select @@變量名
– 修改某個全局變量: set @@變量名=值
– 2) 會話變量。變量只在某次登錄的會話中有效!退出連接,會話變量數據失效!!
– 查看某個會話變量: select @變量名
– 修改/定義某個會話變量: set @變量名=值
– 案例:演示查詢和更改會話變量
– 3) 局部變量:在存儲過程中定義的變量。存儲過程結束局部變量失效!!
– 查看某個局部變量: select 變量名
– 修改某個局部變量: set 變量名=值
– 定義某個局部變量: declare 變量名 數據類型;
– 定義會話變量去接收輸出參數數據
– set @n=’eric’;
CALL pro_testByOut(@n);
– 查看會話變量n
SELECT @n;
– 3.3 帶有輸入輸出參數的存儲過程
DELIMITER $
CREATE PROCEDURE pro_testByInOut(INOUT n VARCHAR(20))
BEGIN
-- 查看n變量
SELECT n;
-- 修改n變量
SET n = '500';
END $
– 定義會話變量調用存儲過程
SET @n='100';
CALL pro_testByInOut(@n);
-- 查看n
SELECT @n;
– 3.4 帶有判斷條件的存儲過程
– 需求: 輸入一個num整數,num=1 ,輸出‘星期一’,num=2,輸出‘星期二’,num=3,輸出‘星期三’,否則,輸出‘錯誤參數’
DELIMITER $
CREATE PROCEDURE pro_testByIf(IN num INT,OUT str VARCHAR(20))
BEGIN
IF num=1 THEN
SET str = '星期一';
ELSEIF num= 2 THEN
SET str ='星期二';
ELSEIF num=3 THEN
SET str = '星期三';
ELSE
SET str = '錯誤參數';
END IF;
END $
CALL pro_testByIf(5,@str);
SELECT @str;
– 3.5 帶有循環條件的存儲過程
– 需求: 輸入一個num,計算從1到num的總和。
DELIMITER $
CREATE PROCEDURE pro_testByWhile(IN num INT,OUT score INT)
BEGIN
-- int result =0;
-- for(int i=1;i<=100;i++){
-- result += i;
-- }
-- 定義局部變量
DECLARE i INT DEFAULT 1;
DECLARE result INT DEFAULT 0;
WHILE i<=num DO
SET result = result + i;
SET i = i+1;
END WHILE;
SET score = result;
END $
CALL pro_testByWhile(200,@score);
SELECT @score;
– 3.6 攜帶數據庫的數據給輸出參數(INTO)
– 需求: 傳入員工id,查詢對應的員工,輸出員工姓名
DELIMITER $
CREATE PROCEDURE pro_testByData(IN eid INT,OUT sname VARCHAR(20))
BEGIN
SELECT NAME INTO sname FROM employee WHERE id=eid;
END $
CALL pro_testByData(2,@sname);
SELECT @sname;ss
– 練習
存儲過程練習
在student表的數據基礎上,設計一個存儲過程:
1)計算出所有學生的英語平均分
2)
如果平均分,大於80分,且小於等於100分,輸出'優秀'
如果平均分,大於等於60分,且小於等於80分,輸出'良好'
如果平均分,小於60分,輸出'不及格'
USE day14;
SELECT * FROM student2;
DELIMITER $
CREATE PROCEDURE pro_testByAvg(OUT str VARCHAR(20),OUT tavg FLOAT)
BEGIN
DECLARE savg FLOAT DEFAULT 0.0;
SELECT AVG(english) INTO savg FROM student2;
IF savg>80 AND savg<=100 THEN
SET str = '優秀';
ELSEIF savg>=60 AND savg<=80 THEN
SET str = '良好';
ELSE
SET str = '不及格';
END IF;
SET tavg = savg;
END $
-- 刪除存儲過程
DROP PROCEDURE pro_testByAvg;
CALL pro_testByAvg(@str,@tavg);
SELECT @str;
SELECT @tavg;
5 觸發器
5.1 簡介
當往員工表插入/修改/刪除一條數據的時候,同時往日誌表記錄下來,這時就要使用觸發器完成。
5.2 觸發器語法
– 員工日誌表
CREATE TABLE emp_log(
id INT PRIMARY KEY AUTO_INCREMENT,
content VARCHAR(20)
)
– 需求: 當往員工表插入一條數據時,往員工日誌插入一條記錄。
– 創建增加觸發器
CREATE TRIGGER tri_empAdd AFTER INSERT ON employee FOR EACH ROW
INSERT INTO emp_log(content) VALUES('員工被插入了一條記錄');
– 創建修改觸發器
CREATE TRIGGER tri_empUpd AFTER UPDATE ON employee FOR EACH ROW
INSERT INTO emp_log(content) VALUES('員工被修改了一條記錄');
– 創建刪除觸發器
CREATE TRIGGER tri_empDel AFTER DELETE ON employee FOR EACH ROW
INSERT INTO emp_log(content) VALUES('員工被刪除了一條記錄');
DROP TRIGGER tri_empAdd;
SELECT * FROM employee;
SELECT * FROM emp_log;
INSERT INTO employee(NAME,deptId,bossId) VALUES(‘李七’,5,1);
UPDATE employee SET NAME=’張三’ WHERE id=10;
DELETE FROM employee WHERE id=10;
5.3 數據庫的權限問題
– 五、mysql權限問題
– root用戶: 超級管理員。 權限: 增刪改查(數據庫,表,數據)
– 給mysql數據庫分配不同權限的不同用戶
– mysql數據庫:存放mysql配置信息,包括用戶信息
USE mysql;
– 用戶表
SELECT * FROM USER;
– 加密函數(md5算法–單向加密)
SELECT PASSWORD('root');
-- *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B
– 修改用戶密碼
UPDATE USER SET PASSWORD=PASSWORD('123456') WHERE USER='root';
– 分配權限給不同的用戶
– 需求: 分配查詢day15數據庫的employee表的權限給eric用戶,密碼爲‘123456’
GRANT SELECT ON day15.employee TO 'eric'@'localhost' IDENTIFIED BY '123456';
GRANT DELETE ON day15.employee TO 'eric'@'localhost' IDENTIFIED BY '123456';
SHOW TABLES;