MySQL入門


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模型

https://www.draw.io/

  • 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這種情況。

上面兩個問題:

  1. 把多表查詢語句可以替換成單表查詢語句【需要優化的情況】
  2. 把重復的字段名,分別使用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='白楊';

練習:

  1. 查詢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;
​ ```

  1. 查詢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班上大於平均年齡的學生

使用 子查詢:

  1. 查詢406班學生平均年齡
  2. 查詢大於平均年齡的學生

查詢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()之后


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM