數據約束
1.數據約束:給表添加一些數據約束從而可以達到約束用戶操作數據的效果。
2.默認值約束(default)
當給這個字段沒有添加值的時候,會給一個默認值,如果給默認值約束的字段添加的值爲null的時候,那麼他的字段值就爲null
– 創建一個stu表
CREATE TABLE stu(
id INT,
NAME VARCHAR(20),
– 給性別gender這個字段添加一個默認值約束
gender VARCHAR(2) DEFAULT '男'
);
– 給stu表中添加幾個數據
INSERT INTO stu VALUES(1,'張八','男');
INSERT INTO stu(id,NAME) VALUES(2,'趙九');
– 給stu表中插入數據,性別爲null
INSERT INTO stu VALUES(3,'劉十',NULL);
3.非空約束(not null):插入的字段不爲null,而且必須插入數據。
CREATE TABLE stu(
-- 給stu表中的id字段添加一個非空約束
id INT NOT NULL,
NAME VARCHAR(20),
gender VARCHAR(2)
);
– 給這張表中添加一個元素,不插入id字段的值
INSERT INTO stu(NAME,gender) VALUES('郭德綱','男');
– 給這張表添加一條數據,id字段的值直接給成null,這樣的話是插入不進去的。
4.唯一約束(unique)
– 給stu表添加一個唯一約束
CREATE TABLE stu(
-- 給stu表中的id字段添加唯一約束
id INT UNIQUE,
NAME VARCHAR(20),
gender VARCHAR(2)
);
– 給表中插入兩條id相同的數據
INSERT INTO stu VALUES(1,'劉德華','男');
INSERT INTO stu VALUES(1,'張學友','男');
– 給表中插入一條id爲null的數據,當給id添加了唯一約束之後,依然可以給他插入多條null值,不會出現重複
INSERT INTO stu VALUES(NULL,'吳奇隆','男');
INSERT INTO stu VALUES(NULL,'劉詩詩','女');
5.主鍵約束(primary key)
經過我們的分析,我們認定我們的這個id字段(唯一+非空)–主鍵(primary key)
注意:
(1)一般來說我們需要給每一張表都設定一個主鍵字段(非空+唯一),用來標示一條信息的唯一性;
(2)我們一般不會將業務字段設定爲主鍵字段,比如name字段,一般我們會給每一張表添加一個id字段作爲主鍵字段;
(3)建議給每張表添加一個主鍵字段,用來標示每一條數據的唯一性。
CREATE TABLE stu(
-- 給stu表中的id字段設置爲主鍵(唯一+非空)
id INT PRIMARY KEY,
NAME VARCHAR(20),
gender VARCHAR(2)
);
– 給表中插入兩條id爲1的學生信息
INSERT INTO stu VALUES(1,'華仔','男');
INSERT INTO stu VALUES(1,'華建','男');
– 給表中插入id爲null的元素
INSERT INTO stu VALUES(NULL,'杰倫','男');
上面的實驗我們可以得出結論,當我們給id字段設置了主鍵約束後,這個id字段就非空+唯一了。
6.自增長約束(auto_increment)
– 給stu表中的id字段添加一個主鍵自增長約束
CREATE TABLE stu(
-- 給stu表中的id字段設置主鍵自增長約束,我們其實就將id這個字段交給了數據庫自己去維護,我們自己不需要去動他
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
gender VARCHAR(2)
);
– 給stu表中添加兩條數據
INSERT INTO stu(NAME,gender) VALUES('華仔','男');
INSERT INTO stu(NAME,gender) VALUES('周杰倫','男');
INSERT INTO stu(NAME,gender) VALUES('周杰倫','男');
INSERT INTO stu(NAME,gender) VALUES('周杰倫','男');
– 刪除id爲4的數據
DELETE FROM stu WHERE id=4;
– 給表中添加一條數據
INSERT INTO stu(NAME,gender) VALUES('張學友','男');
– delete from 這種刪除數據的方式,無法重置自增長的主鍵
– 刪除stu的全表數據
DELETE FROM stu;
– 添加一條數據
INSERT INTO stu(NAME,gender) VALUES('張學友','男');
– 刪除全表數據的truncate table 表名 ,刪除全表數據,這種刪除全表數據的方式可以重置主鍵
TRUNCATE TABLE stu;
INSERT INTO stu(NAME,gender) VALUES('華仔','男');
7.外鍵約束
(1)外鍵約束: 約束兩種表的情況,例如:員工表中出現部門名稱的冗餘字段。
(2)如何解決部門名稱冗餘問題?
答案:獨立設計一張部門表,把部門名稱放到部門表中,這是員工表只需要關聯部門的id即可。
(3) 當插入員工表的部門id的時候,可能會出現不存在的部門id,這是非法數據。
(4)如何防止非法數據的插入?
答案: 這是可以把員工表的部門id設置爲外鍵約束。
(5)當有了外鍵約束之後,操作數據的順序如下:
插入數據: 先插入主表的數據,再插入副表數據
修改數據: 先修改主表數據,再修改副表數據
刪除數據: 先刪除副表數據,再刪除主表數據
– 員工表
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);
– 修改數據
UPDATE employee SET deptId=5 WHERE id=2;
– 刪除數據
DELETE FROM dept WHERE id=1;
(6)當有了外鍵之後,應該如何管理數據呢?
– 插入數據: 先插入主表的數據,再插入副表數據
– 修改數據: 先修改主表數據,再修改副表數據
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;
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
-- 外鍵名稱 外鍵字段 參考
)
數據庫設計(簡單入門)
1.引入
需求分析:
原始需求 ->
業務需求
客戶 業務模型:客戶(姓名 登記時間 郵箱 微信號 )
需求設計:
業務模型(客戶業務模型): -> 抽取實體模型: class Customer{name email weixin}
業務模型(客戶業務模型) -> 數據模型:設計數據庫表(customer表: 字段)
2.數據庫的三大範式
-- 第一大範式:要求表中的每一個字段都是一個獨立的不可拆分的字段
-- student表
-- id 姓名(曾用名|現用名) 年齡
-- 1 張翔|張含 30
-- 2 王勇|張剛 40
-- 需求:查詢曾用名中姓張的學生
-- select * from student where name like '張%';
-- 爲了遵守第一大範式,我們可以將上面的student表進行修改
-- id oldName nowName age
-- 1 張翔 張晗 30
-- 2 王勇 張剛 40
-- 第二大範式:一張表只能表達一個意思
-- student
-- id name age 商品id(商品id)
-- 1 郭德綱 40 1
-- 爲了滿足第二大範式,我們在這裏必須重新創建一個商品表
-- product表
-- 商品id 商品名稱
-- 1 紙尿褲
-- 2 刮鬍刀
-- student表
-- id name age
-- 第三大範式:要求表中的每一個字段只能和主鍵有決定性的關係
-- 員工表,這樣做的話不滿足第三大範式
-- 員工id 姓名 部門id 部門名稱
-- 1 郭德綱 1 軟件開發部
-- 2 岳雲鵬 2 軟件維護部
-- 3 劉德華 3 後勤部
-- 上面的表結構不滿足第三大範式,我們對其進行改造,拆分成兩張表
-- 員工表
-- id name deptId
-- 部門表
-- id deptName
-- 當我們降低了數據冗餘之後,就會形成多張表,在我們進行查詢數據的時候,我們是一張表查詢數據快呢?
-- 還是多張表查詢數據快呢?
-- 結論:存儲空間和你的查詢效率之間是一個矛盾的東西,當你降低了數據的冗餘度的時候你的查詢效率就會降低
-- 當數據的存儲空間佔用的比較大的時候,我們不關心數據冗餘這個問題的時候,但是查詢效率比較高
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
多表查詢
1.交叉連接查詢
需求:查詢每一個員工的姓名以及對應的部門名稱
-- 預計結果:
-- 姓名 部門名稱
-- 華仔 軟件開發部
-- 郭德綱 軟件維護部
SELECT NAME,deptName
FROM employee,dept;
分析:實際出現的結果和我們的預想不一樣,實際結果是我們每一個成員都會對應出現每一一部門名稱,這個就是因爲沒有添加多張表的連接條件
出現的結果俗稱笛卡爾乘積,計算公式:每個成員的name字段 乘以 部門表的deptName字段;
1. 1:多表查詢的條件
(1):確定需要查詢那些表
(2):確定需要查詢那些字段
(3):需要足夠的連接條件(連接條件的數據量-1)
2.內連接查詢( 用的最多):查詢時,只有滿足鏈接條件的結果才能顯示出來
需求:查詢員工對應的部門名稱
SELECT e.name,d.deptName
-- 需要查詢的表
FROM employee e,dept d
-- 連接條件
WHERE e.deptId=d.id;
SELECT NAME,deptName
FROM employee e
INNER JOIN dept d
ON e.deptId=d.id;
3.左外鏈接 :優先顯示左表,滿足連接條件就給予顯示,如果不滿足,則顯示結果爲null,
LEFT OUTER JOIN 左邊的表就稱之爲左表,右邊的表的爲右表
需求:查詢員工對應的部門名稱
SELECT deptName,NAME
FROM dept d
LEFT OUTER JOIN employee e
ON e.deptId=d.id;
4.右外連接 : 優先顯示右表,如果滿足條件就顯示滿足的結果,不滿足就顯示null
RIGHTER OUTER 左邊的爲左表,右邊的爲右表
需求:查詢員工對應的部門名稱
SELECT deptName,NAME
FROM employee e
RIGHT OUTER JOIN dept d
ON e.deptId=d.id;
5.自連接查詢
給員工表插入bossId這個字段,每一個員工對應一個老闆,
需求:查詢每個員工老闆的名字
ALTER TABLE employee ADD COLUMN bossId INT;
SELECT e.name,b.name
FROM employee e,employee b
WHERE e.bossId=b.id;
只能查詢出滿足條件的結果
使用內連接的時候:我們本質上使用一張表,爲了滿足鏈接條件,我們會虛擬出來一張表, 即上述代碼的 employee b .
利用左外鏈接改造上述代碼
SELECT e.name,b.name
FROM employee e
LEFT OUTER JOIN employee b
ON e.bossId=b.id;
存儲過程(類似於Java中的方法)
存儲過程:多個sql語句組成的具有一定邏輯的語句,即sql編程
存儲過程的特點:
1.保存在MySQL數據庫的服務端
2.我們可以直接在客戶端發送指令,去調用我們在服務端的存儲過程
3.存儲過程的移植性非常差
當我們需要程序一個員工的信息的時候,我們可以
SELECT * FROM employee WHERE id=2;
SELECT * FROM employee WHERE id=3;
SELECT * FROM employee WHERE id=4;
這樣顯非常麻煩 ,於是我們可以將上述過程抽取成爲一個存儲過程,然後再去調用它
(1)存儲過程的語法
-- delimiter $ -- 聲明一個結束符
-- create procedure pro_Test(輸入或者輸出參數)
-- begin
-- 帶有邏輯的sql語句
-- end$
-- 以上爲基本格式
-- 調用存儲過程:
-- call pro_Test(實參);
-- 存儲過程的輸入輸出參數如何表示呢?
-- in 輸入參數的變量名稱 類型
-- out 輸出參數的名稱 類型
-- inout 輸入輸出參數名稱 類型
(2) 創建一個帶有輸出參數的存儲過程,並調用
DELIMITER $
CREATE PROCEDURE pro_QueryEmpById(IN eId INT)
BEGIN
SELECT * FROM employee WHERE id=eId;
END$
-- 調用上面的帶有輸入參數的存儲過程
-- 需求,查詢id爲4的員工信息
CALL pro_QueryEmpById(4);
(3) 當我們在調用一個輸出參數的存儲過程的時候,總會有一個返回值的,我們應該利用什麼來接受這個返回值,數據庫中有哪些變量可以供我們使用?
-- 1.全局變量(mysql數據庫的系統變量):隨着mysql數據庫的啓動而存在,隨着mysql數據庫的關閉二消失
-- 查看mysql數據庫的全局變量
SHOW VARIABLES;
-- 查看mysql數據庫中全部變量和字符相關的
SHOW VARIABLES LIKE 'character%';
-- 如何去查看mysql數據庫的全局變量
-- select @@+全局變量名
-- 如何去改變數據庫的全局變量
-- set @@+全局變量=值
SELECT @@character_set_client;
SET @@character_set_client='utf8';
-- 2.會話變量:存在於某一次會話中,隨着會話的結束而消失
-- 如何去查看一個會話變量
-- select @+變量名
-- 給會話變量設置值
-- set @變量名=值
SET @n='hello';
SELECT @n;
-- 3.局部變量:位於存儲過程中,隨着存儲過程而存在,隨着存儲過程的調用完畢二消失
-- 給局部變量設置值
-- set 局部變量=值
-- 查看局部變量
-- select 局部變量
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
(4)創建一個帶有輸出參數的存儲過程
DELIMITER $
CREATE PROCEDURE pro_TestOut(OUT str VARCHAR(20))
BEGIN
-- 給輸出參數賦值
SET str='我是輸出參數';
END$
在調用這個存儲過程時,它會返回一個字符串值
我們應該來定義一個回話變量,用來接受這個值
CALL pro_TestOut(@nn)
SELECT @nn;
(5)創建一個帶有判斷的存儲過程
DELIMITER $
CREATE PROCEDURE pro_TestDay(IN num INT,OUT d VARCHAR(20))
BEGIN
IF num=1 THEN
SET d='星期一';
ELSEIF num=2 THEN
SET d='星期二';
ELSEIF num=3 THEN
SET d='星期三';
ELSE
SET d='參數錯誤';
END IF;
END$
-- 調用上面的這個帶有輸入和輸出參數的存儲過程
CALL pro_TestDay(4,@d);
SELECT @d;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
(6)創建一個帶有循環過程的存儲過程
-- 需求: 輸入一個num,計算從1到num的總和。
DELIMITER $
CREATE PROCEDURE pro_TestSum(IN num INT,OUT score INT)
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE res INT DEFAULT 0;
WHILE i<=num DO
SET res=res+i;
SET i=i+1;
END WHILE;
-- 將局部變量res的值賦值給score
SET score=res;
END$
-- 調用上面的存儲過程
CALL pro_TestSum(200,@score);
SELECT @score;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
(7)攜帶數據庫的數據給輸出參數(into),本質上就是把一個給另一個參數的賦值過程
DELIMITER $
CREATE PROCEDURE pro_QueryNameById(IN eId INT,OUT eName VARCHAR(20))
BEGIN
SELECT NAME INTO eName FROM employee WHERE id=eId;
END$
-- 調用這個存儲過程
CALL pro_QueryNameById(2,@eName);
SELECT @eName;
(8)刪除存儲過程
drop + 存儲過程名
DROP PROCEDURE pro_QueryEmpById;
觸發器
當我們在向一張表中,插入,刪除,修改數據的時候,我們可以將這些操作記錄在一張表上,這就需要觸發器
CREATE TABLE empLog(
id INT PRIMARY KEY AUTO_INCREMENT,
content VARCHAR(20)
);
CREATE TRIGGER tri_empInsert AFTER INSERT ON employee FOR EACH ROW
INSERT INTO empLog(content) VALUES('員工表中被插入一條數據');
INSERT INTO employee(NAME) VALUES('周華健');
CREATE TRIGGER tri_empUpdate AFTER UPDATE ON employee FOR EACH ROW
INSERT INTO empLog(content) VALUES('員工表中被修改一條數據');
UPDATE employee SET NAME='成龍' WHERE id=7;
CREATE TRIGGER tri_empDelete AFTER DELETE ON employee FOR EACH ROW
INSERT INTO empLog(content) VALUES('員工表中被刪除一條數據');
DELETE FROM employee WHERE id=7;
SELECT * FROM empLog;
SELECT * FROM employee;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
注意:每個觸發器的功能是不一樣的,我們必須用不同的觸發器來記錄不同的操作!
數據庫的權限問題
1. root用戶:是我們的超級管理員,擁有所有的權限管理,它可以對我們的(數據庫,表,數據)進行增刪改查。
查詢mysql數據庫的用戶信息
SELECT * FROM USER;
- 當我們查看我們的用戶密碼的時候,發現它並不是我們原來的密碼,這個是因爲數據庫對我們的密碼使用了MD5單向加密算法 。
加密函數是 :password();
SELECT PASSWORD('root');
- 如何修改我們的密碼信息
UPDATE USER SET PASSWORD=PASSWORD('root') WHERE USER='root';
注意:第一個password是一個定義的一個變量,第二個password是我門的password函數
4. 我們也可以爲一些用戶分配不同的權限,方便管理我們的數據庫
GRANT SELECT ON day20.employee TO 'eric'@'localhost' IDENTIFIED BY '123456';