1. 數據庫的介紹
數據庫就是一個以某種有組織的方式存儲的數據集合。
簡單的說,數據庫(database)就是一個存放數據的倉庫,這個倉庫是按照一定的數據結構(數據結構是指數據的組織形式或數據之間的聯系)來組織、存儲的,我們可以通過數據提供的多種方法來管理數據庫里的數據。
好處:
- 持久化存儲
- 讀寫速度極高
- 保證數據的有效性
- 對程序支持性非常好,容易擴展
我們可以理解為,數據庫就是一種特殊的文件,其中存儲着需要的數據。
2. 數據庫的類型
關系型數據庫(RDBMS)
RDBMS
即關系數據庫管理系統(Relational Database Management System)
oracle、mysql、ms sql server、sqlite
關系型數據庫:數據庫里面的數據全部存在數據表中,而這些表在存儲的過程中,各自之間有內在聯系。因為這種聯系,我們稱這樣的數據庫叫"關系型數據庫"
優點:
容易理解,二維表結構
使用方便,通用的SQL語言使得操作關系型數據庫非常方便,便於復雜的查詢
支持事務等復雜的數據操作功能
非關系型數據庫(NoSQL)
NoSQL(NoSQL = Not Only SQL ),意即"不僅僅是SQL"。
MongoDB,Redis
優點:
數據之間無關系,容擴展
結構簡單,具有非常高的讀寫性能,在大數據量下,同樣表現優秀
無需事先建立字段,隨時可以存儲自定義的數據格式
關系型數據庫核心元素
- 數據行(記錄)
- 數據列(字段)
- 數據表(數據行的集合)
- 數據庫(數據表的集合)
例: 一個學生表,(表、字段、列、行)
學號 | 姓名 | 性別 |
---|---|---|
1 | 小明 | 男 |
2 | 小紅 | 女 |
3 | 大白 | 男 |
4 | 小白 | 男 |
3. MySQL的基本介紹
MySQL 是一個關系型數據庫管理系統,由瑞典 MySQL AB 公司開發,目前屬於 Oracle 旗下公司。MySQL 最流行的關系型數據庫管理系統,在 WEB 應用方面 MySQL 是最好的 RDBMS (Relational Database Management System,關系數據庫管理系統) 應用軟件之一。
MySQL 軟件采用了雙授權政策(本詞條“授權政策”),它分為社區版和商業版,由於其體積小、速度快、總體擁有成本低,尤其是開放源碼這一特點,一般網站軟件的開發都選擇 MySQL 作為網站數據庫。
MySQL是一種客戶端/服務器端(C/S)的軟件,我們要學會如何如何安裝服務器端的MySQL,還需要學會如何利用客戶端工具操作MySQL數據,常用的客服端工具有: 命令行、pycharm-database、Navicat等
官網:https://www.mysql.com/
下載:https://dev.mysql.com/downloads/windows
所用mysql文件下載
鏈接: https://pan.baidu.com/s/1fpr0iPs-XhccF6dqUUBKXg 提取碼: yzmj
4. 常用入門的操作命令
mysql -uroot -p密碼 命令行鏈接 mysql
status; 查看數據狀態信息
exit、quit 退出數據庫連接
show databases; 顯示所有的數據庫
create database data charset=utf8; 新創建一個數據庫
use 數據庫名; 選擇要編輯的數據庫,例如是data,則語句就是 use data;
select database(); 查看當前在哪個數據庫下
show tables; 展示數據庫下所有的表
\c 當你輸入有誤,想重打的時候可以試試加個 \c 取消
source 數據庫文件名.sql; 導入數據庫到mysql中
可以把別人事先創建好的數據庫文件導入到當前電腦的mysql中
desc `表名`; 查看表結構信息
鍵盤的上下鍵,可以快速滾回我們之前輸入的代碼。
SQL
SQL,指結構化查詢語言,全稱是 Structured Query Language,是一種 ANSI(American National
Standards Institute 美國國家標准化組織)標准的計算機語言,可以讓我們可以處理數據庫。
SQL語句主要分為:
- DQL:數據查詢語言,用於對數據進行查詢,如select
- DML:數據操作語言,對數據進行增加、修改、刪除,如insert、udpate、delete
- DDL:數據定義語言,進行數據庫、表的管理等,如create、drop
- TPL:事務處理語言,對事務進行處理,包括begin transaction、commit、rollback
- DCL:數據控制語言,進行授權與權限回收,如grant、revoke
- CCL:指針控制語言,通過控制指針完成表的操作,如declare cursor
基本書寫規則
1、每一條語句都要以 " ; " 英文分號結尾
2、SQL語句不區分關鍵字的大小寫,但是建議屬於SQL語句的語法規則用大寫,自建的表、字段小寫。
3、字符串跟日期類型的值都要以 單引號括起來
4、單詞之間需要使用半角的空格隔開
5、我們可以通過使用 `` 反引號來括起表名跟字段名,避免跟關鍵字沖突,但是應該數據庫設計就已經避免這個問題了。
DQL數據查詢語言
查詢 SELECT
select 字段1,字段2 from 表名 從指定表中查詢所有數據的字段1和字段2信息
按條件查詢數據
select 字段1,字段2 from 表名 WHERE 字段名 = 字段值;
1、查找學生表的姓名跟年齡
SELECT name,age FROM student;
查找課程表中的id,課程名稱和教室編號
select id,course,address from course;
2、查找學生表所有的信息
SELET * FROM student;
3、為字段名設置別名,簡化字段名
SELECT name AS n,age AS a FROM student;
4、使用條件查詢想要的數據,查學號為14的學生姓名
SELECT name FROM student WHERE id = 14;
使用條件查詢名字叫'吳傑'的學生姓名和年齡
SELECT name,age FROM student WHERE name='吳傑';
注意:應該根據你的實際需求查詢所要的字段值,而不是使用 * ,使用這個效率很低。
邏輯運算符
運算符 | 含義 |
---|---|
AND | 並列,如果組合的條件都是TRUE,返回TRUE |
OR | 或者,如果組合的條件其一是TRUE,返回TRUE |
NOT | 取反,如果條件是FALSE,返回TRUE |
1、查詢年齡大於10歲小於18歲的學生
SELECT * FROM student WHERE age<18 ADN age>10;
查詢年齡小於18歲 或者性別是女的學生
select name,age,description as des from student where age<18 or sex=2;
查詢年齡在18-22之間的女生信息(班級、姓名、年齡和性別)
select class,name,age,sex from student where age>=18 and age<=22 and sex=2;
查詢309班的所有男生信息(姓名、年齡、個性簽名)
select name,age,description from student where class=309 and sex=1;
查詢306班、305班、304班的學生信息(姓名、年齡、個性簽名)
select name,age,description from student where class=304 or class=305 or class=306;
范圍運算符 (BETWEEN...AND... )
判斷字段值是否在指定區間內
1、 查詢年齡在18-22之間的學生(班級、姓名、年齡和性別)
SELECT class,name,age,sex FROM student WHERE age BETWEEN 18 AND 22;
2、 當然,反過來查的話,查詢18-22歲以外的學生
SELECT class,name,age,sex FROM student WHERE NOT age BETWEEN 18 AND 22;
比較運算符
運算符 | 含義 |
---|---|
= | 等於,判斷字段名的值是否等於指定值 |
<>、!= | 不等於 |
<= | 小於或等於 |
>= | 大於或等於 |
< | 小於 |
> | 大於 |
1、查詢小於等於19歲的學生
SELECT * FROM student WHERE age<=18;
IN運算符(多條件值查詢)
IN 運算符 允許在 WHERE 子句中規定多個值。
1、查詢304,305和306班級的學生信息
select name,class,age from student where class IN (304,305,306)
2、查詢學號為 1、3、5的學生信息
SELECT * FROM student WHERE id IN(1,3,5);
模糊查詢
LIKE 運算符 允許我們針對只知道部分字符串的情況下,查找所有的字符串,進行模糊查找
% 匹配任意多個字符 陳%
_ 匹配任意一個字符 陳__
1、查詢姓陳的學生
SELECT * FROM student WHERE name LIKE '陳%';
查找名字以風字結尾的學生
select * from student WHERE name LIKE '%風';
2、查詢姓名中帶林的學生
select * from student where name LIKE '%林%';
查詢姓名是2個文字組成的學生
select * from student where name LIKE '__';
聚合運算
AVG 返回指定列的平均值
COUNT 返回指定列中非NULL值的個數
MIN 返回指定列的最小值
MAX 返回指定列的最大值
SUM 返回指定列的所有值之和
聚合運算都是寫在select 后面
SELECT COUNT("字段") FROM 表名 WHERE 條件;
1、查詢305班所有的學生數量
select COUNT(id) from student where class=305;
# 上面查詢結果中,字段會變成COUNT('id'),可以使用as別名來處理一下。
select COUNT(id) as c from student where class=305;
2、查詢所有學生中最小的年齡
SELECT MIN(age) FROM student;
3、查詢302班中所有學生的平均年齡。
select AVG(age) from student where class=302;
分組查詢
GROUP BY子句, 可以對表進行分組,常常與聚合函數一起使用
GROUP BY 字段名,當前這個字段名在表中出現多少個不同的字段值,那么查詢結果就會有多少個組。
1、查詢表中有多少男女學生
SELECT sex,count(sex) FROM student GROUP BY sex;
2、查詢學生表中各個年齡段的學生數量
SELECT age,COUNT(name) FROM student GROUP BY age;
3、查詢各個班級的人數各是多少
select class,COUNT(id) FROM student GROUP BY class;
結果排序
ORDER BY 子句,對查詢結果排序
ASC表示升序(從小到大),為默認值,
DESC為降序(從大到小)
1、對309班級的學生的年齡進行倒敘排序
select name,age,sex from student where class=309 order by age desc;
補充:
結果排序可以多個字段排序
例如:對學生的年齡進行降序排列。
select id,name,sex from student order by age desc,id asc limit 10;
# 上面就有2個排序的字段,
# 系統會優先針對 age 進行降序排列,
# 當age的值一致的時候,系統會按照id進行升序排列。
結果限制
LIMIT 子句,可以對查詢出的結果進行數量限制,往往我們不想一次取出所有的數據
limit有兩個使用方式:
limit后面跟着 一個參數 表示限制結果的數量
limit后面跟診 兩個參數,第一個參數表示取數據的開始下標[在表中下標從0開始],第二個參數表示限制結果的數量。
SELECT * FROM student LIMIT 3; // 等同於 limit 0,3 # 下標 0,1,2
SELECT * FROM student LIMIT 3,3; // 等同於 limit 3,3 # 下標 3,4,5
SELECT * FROM student LIMIT 6,3; // 等同於 limit 6,3 # 下標 6,7,8
1、查詢出年級最大的10個學生
select * from student order by age desc,id asc limit 10;
2、從所有學生中,查詢年級最大的下標從10-19的學生出來。
select id,name,age from student order by age desc,id asc limit 10,10;
limit 主要用於在項目開發中的分頁功能實現。
DML
添加數據(INSERT )
添加一名記錄
INSERT INTO 表名 (字段1,字段2,字段3,....) VALUES (字段值1,字段值2,字段值3,....);
# 也可以省略不寫字段名,但是數據的數據項必須和表結構的字段數量保持一致,查詢表結構使用 desc 表名;
INSERT INTO 表名 VALUES (字段值1,字段值2,字段值3,....);
insert into student (id,name,sex,class,age,description) values (101,'劉德華',1,508,17,'給我一杯忘情水~');
# 上面的字段,如果是全部字段,那么字段這一塊內容可以省略不寫。
# 例如,我們再次添加一個學生,如果省略了字段名,那么填寫數據的數據項必須和表結構的字段數量保持一致。
insert into student values (102,'張學友',1,508,17,'愛就像頭餓狼~',0,0,0);
添加多名學生
INSERT INTO student(name,sex,class,age,description) VALUES ('周潤發',1,508,17,'5個A~'),('周傑倫',1,508,17,'給我一首歌的時間~');
注: 自動增長跟有默認值的字段可以不寫。
更新數據(UPDATE)
UPDATE 表名 SET 字段1=字段值1,字段2=字段值2 WHERE 條件
# 更新操作會影響數據的不可逆操作,所以更新的時候,一定要謹慎,添加條件。如果沒有條件,
# 或者條件的判斷結果一直是True,則整個表所有的記錄都會被更新。
修改學生的姓名,年齡
UPDATE student set age=8 where id=104;
刪除數據(DELETE)
DELETE FROM 表名 WHERE 條件
刪除一個學生
DELETE FROM student WHERE id=104;
注: 修改跟刪除數據都要記得加條件。
DELETE FROM table 刪除整個表的內容[沒有條件則表示刪除整個表所有數據]
DDL
DROP TBALE 表名 刪除整個表
刪除學生表
DROP TABLE student;
刪除學生表的數據
DELETE FROM student;
TRUNCATE table 清空/重置表[表還在數據被清空了]
create database 數據庫名 charset=utf8; 創建數據庫
drop database 數據庫名 刪除數據庫[一定要謹慎操作]
5 DDL
創建表
CREATE TABLE 表名(
字段名1 數據類型 約束規則,
字段名2 數據類型,
字段名3 數據類型,
.....
字段名N 數據類型,
PRIMARY KEY(一個 或 多個 字段名)
);
# 上面語句中,最后一個小句子后面不能有英文逗號出現,前面的小句子必須加上英文逗號。
字段名
定義字段名,表名、數據庫名、規范:
在64個字符以內,建議簡短,如果不夠清晰,可以使用前綴。
不能是關鍵字或者保留字
采用變量命名方式[ 由字母、數字、下划線組成,不能以數字開頭 ]
數據類型
數據庫里面的數據在保存時,也要通過數據類型來告訴系統,這些數據的用途,所以也會有對應的數據類型:
數值類型[整數和浮點數]、字符串 和 日期
約束規則
是否唯一[數據在同一個表中的同一列中是否可以出現多個]
是否無符號[約束當前是否可以填寫負數,有符號可以填寫,無符號不能填寫。]
是否設置為當前表的主鍵[主鍵是一個表記錄不同行數據之間的唯一字段,這個字段必須是唯一的]
是否自動增長[添加數據的時候,如果不填寫這個字段,那么這個字段會自動在之前已有的值基礎上+1填充]
設置默認值[ 添加/修改數據時,如果值沒有填寫或者被清空了,采用指定的值作為字段值 ]
是否可以填寫空(null,等同於python里面的None)值
創建班級表
create table classes(
id int unsigned auto_increment primary key not null,
name varchar(10)
);
例如:創建學生表[原來的數據庫中已經存在了一張表,所以練習案例的時候注意,建議新建一個數據庫來創建]
mysql> create table student(
-> id int unsigned auto_increment not null, # 字段名 整型 無符號 自動增長 不能是空,
-> name char(10), # 字段名 字符串(長度:10)
-> sex int default 1, # 字段名 整型 默認值為 1,
-> class int, # 字段名 整型
-> age int, # 字段名 整型
-> description text, # 字段名 文本[可以填寫65535個字符]
-> primary key(id) # 設置主鍵(id) 每個表必須都有主鍵
-> ) engine=innodb charset=utf8; # 表引擎=innodb 編碼=utf8;[后面學習,先用]
Query OK, 0 rows affected (0.02 sec) # 出現這句話,表示創建表成功
mysql> desc student; # 顯示表結構
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | char(10) | YES | | NULL | |
| sex | int(11) | YES | | 1 | |
| class | int(11) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| description | text | YES | | NULL | |
+-------------+------------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
自己動手創建一個課程表
create table `course`(
id int unsigned not null auto_increment,
course char(20) not null,
lecturer int unsigned,
address int unsigned,
primary key(id)
) engine=innodb charset=utf8;
數據庫操作記錄:
mysql> create table `course`(
-> id int unsigned not null auto_increment,
-> course char(20) not null,
-> lecturer int unsigned,
-> address int unsigned,
-> primary key(id)
-> ) engine=innodb charset=utf8;
Query OK, 0 rows affected (0.01 sec)
顯示建表語句
show create table 表名 \G;
mysql> show create table course \G;
*************************** 1. row ***************************
Table: course
Create Table: CREATE TABLE `course` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`course` char(20) NOT NULL,
`lecturer` int(10) unsigned DEFAULT NULL,
`address` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
修改表-添加字段
alter table 表名 add 列名 類型;
例:
alter table students add birthday datetime;
修改表-修改字段:重命名版
alter table 表名 change 原名 新名 類型及約束;
例:
alter table students change birthday birth datetime not null;
修改表-修改字段:不重命名版
alter table 表名 modify 列名 類型及約束;
例:
alter table students modify birth date not null;
修改表-刪除字段
alter table 表名 drop 列名;
例:
alter table students drop birthday;
刪除表
drop table 表名;
例:
drop table students;
查看表的創建語句
show create table 表名\G;
例:
show create table student\G;
6 數據類型
了解數據的數據類型可以通過以下語句來查看和使用幫助:
mysql> ? 查詢關鍵詞
# 如果,我們希望了解關於int的可以填值范圍
mysql> ? int
使用數據類型的原則:夠用就行,盡量使用取值范圍小的,而不用大的,這樣可以更多的節省存儲空間
-
常用數據類型如下:
- 整數:bit[0-64],tinyint, smallint, int
- 小數:decimal
- 字符串:varchar,char
- 日期時間: date, time, datetime
- 枚舉類型(enum) 多選一,例如性別字段 enum('男','女'),后面添加數據時,值得填寫只能'男'和'女'這兩項,其他值填寫進來會報錯。
-
特別說明的類型如下:
- decimal表示浮點數,如decimal(5,2)表示共存5位數,小數占2位
- char表示固定長度的字符串,如char(3),如果填充'ab'時會補一個空格為
'ab '
- varchar表示可變長度的字符串,如varchar(3),填充'ab'時就會存儲'ab'
- 字符串text表示存儲大文本,當字符大於4000時推薦使用
- 對於圖片、音頻、視頻等文件,不存儲在數據庫中,而是上傳到某個文件管理服務器上,然后在表中存儲這個文件的保存路徑
-
更全的數據類型可以參考http://blog.csdn.net/anxpp/article/details/51284106
數值類型(常用)
類型 | 字節大小 | 有符號范圍(Signed) | 無符號范圍(Unsigned) |
---|---|---|---|
TINYINT | 1 | -128 ~ 127 | 0 ~ 255 |
SMALLINT | 2 | -32768 ~ 32767 | 0 ~ 65535 |
MEDIUMINT | 3 | -8388608 ~ 8388607 | 0 ~ 16777215 |
INT/INTEGER | 4 | -2147483648 ~2147483647 | 0 ~ 4294967295 |
BIGINT | 8 | -9223372036854775808 ~ 9223372036854775807 | 0 ~ 18446744073709551615 |
小數類型
類型 | 使用 | 描述 |
---|---|---|
decimal(M,D) | decimal(5,2),表示只能有5個數字, 其中最多設置2個數字在小數點后面 可以存儲的數值:1000.5,123.56 不可以存儲的數值:1000.51,100000, 1.345 |
十進制小數,用於表示商品的價格 |
開發中,一般QQ號或者手機號都是使用字符串來保存的
字符串
類型 | 字節大小 | 示例 |
---|---|---|
CHAR | 0-255 | 定長字符串,類型:char(3) 輸入 'ab', 實際存儲為'ab ', 輸入'abcd' 實際存儲為 'abc' |
VARCHAR | 0-255 | 不定長字符串,類型:varchar(3) 輸 'ab',實際存儲為'ab', 輸入'abcd',實際存儲為'abc' |
TEXT | 0-65535 | 大文本 |
在5.5版本的mysql以后,varchar類型可以存儲的數據,可以達到65535個字符。
日期時間類型
類型 | 字節大小 | 示例 | 場景 |
---|---|---|---|
DATE | 4 | '2020-01-01' | 日期記錄,會員過期時間,活動時間范圍 |
TIME | 3 | '12:29:59' | 餐廳的餐牌 |
DATETIME | 8 | '2020-01-01 12:29:59' | 會員登錄時間 |
YEAR | 1 | '2017' | 電影的年份.... |
TIMESTAMP | 4 | '1970-01-01 00:00:01' UTC ~ '2038-01-01 00:00:01' UTC | 基本用不上 |
DATETIME 和 TIMESTAMP,很多時候,我們會使用程序中的時間戳來代替,后面在數據庫中保存時設置字段的類型是數值型,這樣的話,可以節省存儲空間,同時還可以提高數據的讀取速度。
7 數據庫設計
約束規則
-
主鍵primary key:在表中區分每一行數據的唯一性的標志服,數據在物理上存儲的順序
-
非空not null:此字段不允許填寫空值,如果允許填寫空值,則直接不填not null
-
惟一unique:此字段的值不允許重復
-
默認default:當不填寫此值時會使用默認值,如果填寫時以填寫為准
-
外鍵 foreign key:用於連接兩個表的關系,對關系字段進行約束,當為關系字段填寫值時,會到關聯的表中查詢時是否此值是否存在,如果存在則填寫成功,如果不存在則填寫失敗並拋出異常
-
說明:雖然外鍵約束可以保證數據的有效性,但是在進行數據的crud(create增加、update修改、delete刪除、read查詢)時,都會降低數據庫的性能,所以不推薦使用,那么數據的有效性怎么保證呢?答:可以在python的邏輯層進行判斷控制[用代碼控制]
-
關系型數據庫建議在E-R模型的基礎上,我們需要根據產品經理的設計策划,抽取出來模型與關系,制定出表結構,這是項目開始的第一步
-
在開發中有很多設計數據庫的軟件,常用的如power designer,db desinger等,這些軟件可以直觀的看到實體及實體間的關系
-
設計數據庫,可能是由專門的數據庫設計人員完成,也可能是由開發組成員完成,一般是項目經理帶領組員來完成
-
現階段不需要獨立完成數據庫設計,但是要注意積累一些這方面的經驗
實體
就是我們根據開發需求,要保存到數據庫中作為一張表存在的事物。實體的名稱最終會變成表名
實體會有屬性,實體的屬性就是描述這個事物的內容,實體的屬性最終會在表中作為字段存在。
實體與實體之間會存在關系,這種關系一般就是根據三范式提取出來的主外鍵。
8 三范式
范式理論【在總結了經驗以后,得出規范我們數據庫設計的一些理論】
三范式:
1. 數據要保證不可分割.
2. 數據不能冗余(多余).
3. 數據不能重復.重復的數據,新建一張表存儲.
-
經過研究和對使用中問題的總結,對於設計數據庫提出了一些規范,這些規范被稱為范式(Normal Form)
-
目前有跡可尋的共有8種范式,一般需要遵守3范式即可
-
◆ 第一范式(1NF):強調的是列的原子性,即列不能夠再分成其他幾列。
考慮這樣一個表:【聯系人】(姓名,性別,電話) 如果在實際場景中,一個聯系人有家庭電話和公司電話,那么這種表結構設計就沒有達到 1NF。要符合 1NF 我們只需把列(電話)拆分,即:【聯系人】(姓名,性別,家庭電話,公司電話)。1NF 很好辨別,但是 2NF 和 3NF 就容易搞混淆。
-
◆ 第二范式(2NF):首先是 1NF,另外包含兩部分內容,一是表必須有一個主鍵;二是沒有包含在主鍵中的列必須完全依賴於主鍵,而不能只依賴於主鍵的一部分。
考慮一個訂單明細表:【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName)。 因為我們知道在一個訂單中可以訂購多種產品,所以單單一個 OrderID 是不足以成為主鍵的,主鍵應該是(OrderID,ProductID)。顯而易見 Discount(折扣),Quantity(數量)完全依賴(取決)於主鍵(OderID,ProductID),而 UnitPrice,ProductName 只依賴於 ProductID。所以 OrderDetail 表不符合 2NF。不符合 2NF 的設計容易產生冗余數據。
可以把【OrderDetail】表拆分為【OrderDetail】(OrderID,ProductID,Discount,Quantity)和【Product】(ProductID,UnitPrice,ProductName)來消除原訂單表中UnitPrice,ProductName多次重復的情況。
-
◆ 第三范式(3NF):首先是 2NF,另外非主鍵列必須直接依賴於主鍵,不能存在傳遞依賴。即不能存在:非主鍵列 A 依賴於非主鍵列 B,非主鍵列 B 依賴於主鍵的情況。
考慮一個訂單表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主鍵是(OrderID)。 其中 OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity 等非主鍵列都完全依賴於主鍵(OrderID),所以符合 2NF。不過問題是 CustomerName,CustomerAddr,CustomerCity 直接依賴的是 CustomerID(非主鍵列),而不是直接依賴於主鍵,它是通過傳遞才依賴於主鍵,所以不符合 3NF。 通過拆分【Order】為【Order】(OrderID,OrderDate,CustomerID)和【Customer】(CustomerID,CustomerName,CustomerAddr,CustomerCity)從而達到 3NF。 *第二范式(2NF)和第三范式(3NF)的概念很容易混淆,區分它們的關鍵點在於,2NF:非主鍵列是否完全依賴於主鍵,還是依賴於主鍵的一部分;3NF:非主鍵列是直接依賴於主鍵,還是直接依賴於非主鍵列。
不遵循1NF
不遵循2NF
不遵循3NF
最終表
9 E-R模型
- E表示entry,實體,設計實體就像定義一個類一樣,指定從哪些方面描述對象,一個實體轉換為數據庫中的一個表
- R表示relationship,關系,關系描述兩個實體之間的對應規則,關系的類型包括包括一對一、一對多、多對多
- 關系也是一種數據,需要通過一個字段存儲在表中
實體之間會因為引用相互引用字段而存在關系,這種關系一般有三種:
1-1
1-n
n-m[ 多對多一般表現為2個 1對多 ]
-
實體A對實體B為1對1,則在表A或表B中創建一個字段,存儲另一個表的主鍵值
-
實體A對實體B為1對多:在表B中創建一個字段,存儲表A的主鍵值
-
實體A對實體B為多對多:新建一張表C,這個表只有兩個字段,一個用於存儲A的主鍵值,一個用於存儲B的主鍵值
-
想一想:舉些例子,滿足一對一、一對多、多對多的對應關系
邏輯刪除
- 對於重要數據,並不希望物理刪除,一旦刪除,數據無法找回
- 刪除方案:設置isDelete的列,類型為bit,表示邏輯刪除,默認值為0
- 對於非重要數據,可以進行物理刪除
- 數據的重要性,要根據實際開發決定
示例
- 設計兩張表:班級表、學生表
- 班級表classes
- id
- name
- isdelete
- 學生表students
- id
- name
- birthday
- gender
- clsid
- isdelete
## 10 備份和恢復
### 備份
- 運行mysqldump命令
```sql
mysqldump –uroot –p 數據庫名 > python.sql;
# 按提示輸入mysql的密碼
恢復
- 連接mysql,創建新的數據庫
- 退出連接,執行如下命令
mysql -uroot –p 新數據庫名 < python.sql
# 根據提示輸入mysql密碼
11 消除重復行
- 在select后面列前使用distinct可以消除重復的行
- distinct的使用需要放在第一個字段的位置,針對第一個字段進行去重。
select distinct 列1,... from 表名;
例:
select distinct gender from students;
例如,統計下在學生表的所有的學生班級
select distinct class from student;
12 where條件的運算符進階
空判斷
-
注意:null與''是不同的
-
判空is null
例1:查詢沒有填寫個性簽名的學生
select * from student where description is null;
- 判非空is not null
例2:查詢填寫了個性簽名的學生
select * from student where description is not null;
例3:查詢填寫了身高的男生
select * from student where description is not null and sex=1;
運算符優先級
- 優先級由高到低的順序為:小括號,not,比較運算符,邏輯運算符
- and比or先運算,如果同時出現並希望先算or,需要結合()使用
13 連接查詢[連表查詢、多表查詢]
當查詢結果的列來源於多張表時,需要將多張表連接成一個大的數據集,再選擇合適的列返回
mysql支持三種類型的連接查詢,分別為:
內連接查詢(inner join)
查詢的結果為兩個表匹配到的數據
使用內連接,必須保證兩個表都會對應id的數據才會被查詢出來。
select 字段1,字段2... from 主表 inner join 從表 on 主表.主鍵=從表.外鍵
例如:查詢學生的信息[ 成績、名字、班級 ]
我們給學生表添加一個學生信息,然后使用該學生的主鍵id來連表查詢成績、名字和班級。
insert into student (name,sex,age,class,description) values ('劉德華',1,17,406,'');
select achievement,name,class
from student as a
inner join achievement as b
on a.id=b.sid
where id=101;
# 上面語句因位該學生只在學生表student中有數據,而成績表中沒有數據,所以使用內連接,連表查詢的結果是
Empty set (0.00 sec)
同樣,如果從表有數據,而主表沒有數據,則使用內連接查詢一樣無法查詢到結果。
#例如,添加一個成績記錄,是不存在學生
insert into achievement (sid,cid,achievement) values (102,10,85);
select achievement,name,class
from student as a
inner join achievement as b
on a.id=b.sid
where id=102;
右連接查詢(right join)
只要從表有數據,不管主表是否有數據,都會查詢到結果。[以從表的結果為主]
查詢的結果為兩個表匹配到的數據,右表特有的數據,對於左表中不存在的數據使用null填充
select 字段1,字段2... from 主表 right join 從表 on 主表.主鍵=從表.外鍵
例如,上面的成績id為102的學生, 我們使用右連接查詢。
select achievement,name,class
from student as a
right join achievement as b
on a.id=b.sid;
左連接查詢(left join)
只要主表有數據,不管從表是否有數據都會被查詢出來。
查詢的結果為兩個表匹配到的數據,左表特有的數據,對於右表中不存在的數據使用null填充
語法
select * from 表1 left join 表2 on 表1.列 = 表2.列
例如,使用左連接查詢學生表與成績表,查詢學生姓名及分數
select achievement,name,class
from student as a
left join achievement as b
on a.id=b.sid;
等同於
select achievement,name,class
from achievement as b
right join student as a
on a.id=b.sid;
總結:
三種連表查詢,最常用的是 left join,然后inner join保證數據的一致性。右連接基本上都是使用左連接代替。
多表關聯
select 表.字段1,表.字段2,表.字段3.....
from 主表
left join 從表1 on 主表.主鍵=從表1.外鍵
left join 從表2 on 主表.主鍵=從表2.外鍵
# 這里和從表2連接的on條件看實際情況,也會出現從表1.主鍵=從表2.外鍵的情況
left join 從表3 on 主表.主鍵=從表3.外鍵
# 這里可以是(從表1或從表2).主鍵=從表2.外鍵的情況
left join ...
多表查詢的缺點
多表查詢的效率,性能比單表要差。
多表查詢以后,還會帶來字段多了會引起字段覆蓋的情況、
主表student 從表1 achievement 從表2 course
name xxx name
上面三張表如果連表,則出現主表的name覆蓋從表2的name這種情況。
上面兩個問題:
- 把多表查詢語句可以替換成單表查詢語句【需要優化的情況】
- 把重復的字段名,分別使用as來設置成別的名稱。
例如,查詢白楊的班級、id、年齡和課程名稱以及對應課程的成績
select a.id,a.class,a.age,c.course,b.achievement
from student as a
left join achievement as b on a.id=b.sid
left join course as c on c.id=b.cid
where a.name='白楊';
練習:
-
查詢id為20的學生的考試總分.
```sql
select sum(b.achievement) sum # 有時候as可以不寫
from student as a
left join achievement as b on a.id=b.sid
where a.id=20;
```
- 查詢305班級所有學生的課程名稱、課程成績、以及對應課程的授課老師。
1. 先查305的學生信息
2. 再查305的學生成績
3. 再查305的學生成績對應的課程
4. 最后查305的學生成績對應的課程的老師
select a.name,b.achievement,course,d.name
from student as a
left join achievement as b on a.id=b.sid
left join course as c on b.cid=c.id
left join lecturer as d on d.id=c.lecturer_id
where a.class=305;
上面代碼的效果:
+--------+-------------+----------------+--------+
| name | achievement | course | name |
+--------+-------------+----------------+--------+
| 譚季同 | 100.0 | Photoshop | 唐老師 |
| 譚季同 | 79.0 | 負載均衡 | 杜老師 |
| 譚季同 | 78.5 | Flask項目 | 白老師 |
| 白瀚文 | 73.0 | go | 陳老師 |
| 白瀚文 | 65.0 | webpy | 林老師 |
| 白瀚文 | 86.0 | 數據分析 | 鄭老師 |
| 白瀚文 | 60.0 | API接口 | 宋老師 |
| 晁然 | 0.0 | Flask | 陳老師 |
| 晁然 | 78.0 | Python網絡編程 | 江老師 |
| 晁然 | 78.0 | HTML5 | 丘老師 |
| 白素欣 | 81.0 | Django項目 | 易老師 |
| 白素欣 | 90.0 | Python | 黃老師 |
| 白素欣 | 39.0 | Nginx | 曹老師 |
| 庄曉敏 | 82.5 | Nginx | 曹老師 |
| 庄曉敏 | 68.0 | Python | 黃老師 |
| 庄曉敏 | 100.0 | API接口 | 宋老師 |
+--------+-------------+----------------+--------+
14 單表的連表查詢[自關聯查詢]
核心就是把一張表看做2張表來操作
# 建表:
create table area(
id smallint not null auto_increment comment '主鍵ID',
name char(30) not null comment '地區名稱',
pid smallint not null default 0 comment '父級地區ID',
primary key (id)
) engine=innodb charset=utf8;
insert into area (name,pid) values ('廣東',0),('深圳',1),('龍崗',2),('福田',2),('寶安',2);
格式:
select 字段1,字段2...
from 主表(當前表) as a
left join 從表(當前表) as b on a.主鍵=b.外鍵
查找深圳地區的子地區,SQL代碼:
# 主表看成保存深圳的表,
# 從表看成保存深圳子地區的表
select b.id,b.name
from area as a
left join area as b on a.id=b.pid
where a.name='深圳';
15 子查詢
在一個 select 語句中,嵌入了另外一個 select 語句, 那么被嵌入的 select 語句稱之為子查詢語句
格式:
select 字段 from 表名 where 條件(另一條查詢語句)
主查詢
主要查詢的對象,第一條 select 語句
主查詢和子查詢的關系
- 子查詢是嵌入到主查詢中
- 子查詢是輔助主查詢的,要么充當條件,要么充當數據源
- 子查詢是可以獨立存在的語句,是一條完整的 select 語句
例如:查詢406班上大於平均年齡的學生
使用 子查詢:
- 查詢406班學生平均年齡
- 查詢大於平均年齡的學生
查詢406班級學生的平均身高
select name,age from student where age > (select avg(age) as avg from student where class=406) and class=406;
16 having
group by 字段 having 條件;
過濾篩選,主要作用類似於where關鍵字,用於在SQL語句中進行條件判斷,過濾結果的。
但是與where不同的地方在於having只能跟在group by 之后使用。
練習:查詢301班級大於班上平均成績的學生成績信息(name,平均分,班級)。
# 先求301班的平均成績
select avg(achievement) as achi from student as a
left join achievement as b on a.id=b.sid
where class=301;
# 判斷301中的每個人平均成績大於上面的到的平均成績
select name,avg(achievement) from student as a
left join achievement as b on a.id=b.sid
where class=301 group by name having avg(achievement) > (select avg(achievement) as achi from student as a
left join achievement as b on a.id=b.sid
where class=301);
17 select查詢語句的完整格式
select distinct 字段1,字段2....
from 表名 as 表別名
left join 從表1 on 表名.主鍵=從表1.外鍵
left join ....
where ....
group by ... having ...
order by ...
limit start,count
- 執行順序為:
- from 表名[包括連表]
- where ....
- group by ...
- select distinct *
- having ...
- order by ...
- limit start,count
- 實際使用中,只是語句中某些部分的組合,而不是全部
我們之前學習的source也是一種恢復方式,但是兩種使用有一個區別。就是
mysql 命令這種方式,可以遠程 恢復,而source這種只能本地電腦恢復。
mysql -hIP地址 -uroot -p密碼
18 Python操作mysql
pymysql 一般使用這個
MySQLDB
安裝pymysql模塊
pip install pymysql
使用pymysql模塊操作數據庫
import pymysql
# from pymysql import *
# 創建和數據庫服務器的連接 connection
conn = pymysql.connect(host='localhost',port=3306,user='root',password='root123456',
db='student',charset='utf8')
# 創建游標對象
cursor = conn.cursor()
# 中間可以使用游標完成對數據庫的操作
sql = "select * from student;"
# 執行sql語句的函數 返回值是該SQL語句影響的行數
count = cursor.execute(sql)
print("操作影響的行數%d" % count)
# print(cursor.fetchone()) # 返回值類型是元祖,表示一條記錄
# 獲取本次操作的所有數據
for line in cursor.fetchall():
print("數據是%s" % str(line))
# 關閉資源 先關游標
cursor.close()
# 再關連接
conn.close()
執行語句
#執行sql,更新單條數據,並返回受影響行數
result = cursor.execute("SQL語句")
#插入多條,並返回受影響的函數,例如批量添加
result2 = cursor.executemany("多條數據")
#獲取最新自增ID
new_id = cursor.lastrowid
獲取結果
#獲取一行
result1 = cursor.fetchone()
#獲取多行[參數可以設置指定返回數量]
result2 = cursor.fetchmany(整型)
#獲取所有
result3 = cursor.fetchall()
操作數據
#提交,保存新建或修改的數據,如果是查詢則不需要
conn.commit() # 寫在execute()之后