1. 程式人生 > 其它 >MySQL 01(SQL基礎、約束、多表、事務)

MySQL 01(SQL基礎、約束、多表、事務)

MySQL 01

目錄

一、MySQL基礎

資料庫概述

  • 資料庫:用於儲存和管理資料的倉庫
  • 資料庫的特點:
    1. 持久化儲存資料(資料庫就是一個檔案系統)
    2. 方便儲存和管理資料
    3. 使用統一方式操作資料庫(使用SQL)

配置MySQL

  • MySQL服務啟動(Windows)

    1. 方法一:

      手動啟動或關閉:開啟computer management->Services->MySQL

      快捷開啟Services

      win+R->services.msc

    2. 方法二:

      通過cmd.exe命令列:首先使用管理員開啟cmd.exe

      net start mysql啟動服務

      net stop mysql關閉服務

  • MySQL的登入和退出

    根據實際情況替換以下USERNAME、PASSWORD、IPADDRESS

    1. 本地連線:使用使用者名稱和密碼登入

      • 直接輸入使用者名稱和密碼

        mysql -uUSERNAME -pPASSWORD

      • 後輸入密碼

        mysql -uUSERNAME -p

    2. 遠端連線:使用使用者名稱和密碼登入

      • 直接輸入使用者名稱和密碼(兩種方式)

        mysql -hIPADDRESS -uUSERNAME -pPASSWORD

        mysql --host=IPADDRESS --user=USERNAME --password=PASSWORD

      • 後輸入密碼

        mysql -hIPADDRESS -uUSERNAME -p

    3. 退出

      exit

      quit

資料庫的備份與還原

  • 備份

    cmd命令

    mysqldump -u使用者名稱 -p密碼 資料庫名 > 儲存的路徑

  • 還原

    步驟:

    1. 登入資料庫

    2. 建立資料庫

    3. 使用資料庫

    4. 執行檔案

      source 檔案路徑

MySQL目錄結構

  1. MySQL安裝目錄

    配置檔案:my.ini

  2. MySQL資料目錄

    資料庫:資料夾

    表:檔案

    資料:檔案中儲存的資料

SQL概述

  • SQL(Structured Query Language):結構化查詢語言

    定義了操作所有關係型資料庫的規則,每一種資料庫操作的方式存在不一樣的地方,稱為“方言”

  • SQL通用語法

    1. SQL語句可以單行或多行進行書寫,以分號結尾
    2. 可以使用空格和縮排來增強語句的可讀性
    3. MySQL資料庫的SQL語句不區分大小寫,關鍵字建議使用大寫
    4. 註釋方法:
      • 單行註釋:--空格註釋內容#註釋內容
      • 多行註釋:/*註釋內容*/
  • SQL分類

    • DDL(Data Definition Language)

      用來定義資料庫物件:資料庫,表,列

      關鍵字:create, drop, alter

    • DML(Data Manipulation Language)

      用來對資料庫表中的資料進行增刪改

      關鍵字:insert, delete, update

    • DQL(Data Query Language)

      用來查詢資料庫中表的記錄(資料)

      關鍵字:select, where

    • DCL(Data Control Language)

      用來定義資料庫的訪問許可權和安全級別,及建立使用者

      關鍵字:GRANT, REVOKE

操作資料庫、表(DDL)

  • 資料庫的操作:CRUD

    1. C(Create):建立

      • 建立資料庫

        create database 資料庫名稱;

      • 建立資料庫,判斷不存在,再建立

        create database if not exists 資料庫名稱;

      • 建立資料庫,並指定字符集

        create database 資料庫名稱 character set 字符集名;

      • 示例:建立資料庫,判斷是否存在,並指定 字符集為gbk

        create database if not exists db1 character set gbk;

    2. R(Retrieve):查詢

      • 查詢所有資料庫的名稱

        show databases;

      • 查詢某個資料庫的字符集:查詢某個資料庫的建立語句

        show create database 資料庫的名稱;

    3. U(Update):修改

      • 修改資料庫的字符集

        alter database 資料庫名稱 character set 字符集名稱;

    4. D(Delete):刪除

      • 刪除資料庫

        drop database 資料庫的名稱;

      • 判斷資料庫存在,存在就刪除

        drop database if exists 資料庫名稱;

    5. 使用資料庫

      • 查詢當前正在使用的資料庫名稱

        select database();

      • 使用資料庫

        use 資料庫名稱;

  • 表的操作:CRUD

    1. C(Create):建立

      • 建立表

        create table 表名(
            列名1 資料型別1,
            列名2 資料型別2,
            列名3 資料型別3,
            ...
            列名n 資料型別n
        );
        

        注意:最後一列不加逗號

      • 複製表

        create table 表名dst like 表名src ;

      • SQL中常見的資料型別:

        1. int:整數型別

          age int

        2. double:小數型別

          score double(總共的數字個數, 小數點後的數字個數)

        3. date:日期,只包含年月日, yyyy-MM-dd

        4. datetime:日期,包含年月日時分秒, yyyy-MM-dd HH:mm:ss

        5. timestamp:時間戳,包含年月日時分秒, yyyy-MM-dd HH:mm:ss

          如果將來不給timestamp這個欄位賦值,或賦值為null,則預設使用當前的系統時間,來自動賦值

        6. varchar:字串

          name varchar(最大字元個數)

      • 建立表案例

        create table student (
            id int,
        	name varchar(32),
            age int,
            score double(3, 1),
            birthdate date,
            insert_time timestamp
        );
        
    2. R(Retrieve):查詢

      • 查詢某個表的的字符集:查詢某個表的建立語句

        show create table 表名;

      • 查詢某個資料庫中所有的表名稱

        show tables;

      • 查詢表結構

        desc 表名;

    3. U(Update):修改

      • 修改表名

        alter table 表名 rename to 表名;

      • 修改表的字符集

        alter table 表名 character set 字符集;

      • 新增一列

        alter table 表名 add 列名 資料型別;

      • 修改列名稱和型別

        alter table 表名 change 列名src 列名new 新資料型別;

        同時改一個指定列名的列名和表名

        alter table 表名 modify 列名src 新資料型別;

        只改指定列名的資料型別

      • 刪除列

        alter table 表名 drop 列名;

    4. D(Delete):刪除

      • 刪除表

        drop table 表名;

      • 先判斷,再刪除

        drop table if exists 表名;

增刪表中的資料(DML)

  • 新增資料

    新增一行資料

    insert into 表名 (列名1,列明2...列名n) values(值1, 值2...值n);

    注意:

    1. 列名和值要一一對應

    2. 如果表名後,不定義列名,則預設給所有列新增值

      insert into 表名 values(值1, 值2...值n);

    3. 除了數字型別,其他型別需要使用引號(單雙引號都可以)

    4. 新增多行資料格式

      insert into 表名 (列名1,列明2...列名n) values
      (值1, 值2...值n), 
      (值1, 值2...值n), 
      (值1, 值2...值n), 
      ...
      (值1, 值2...值n);
      
  • 刪除資料

    delete from 表名 where 條件;

    注意:

    delete from 表名;可以直接刪除所有的資料(但是不推薦,有多少條記錄就會有多少次刪除操作)

    TRUNCATE TABLE 表名;先刪除表,然後再建立一張一樣的表(推薦使用,相當於刪除全部資料的操作)

  • 修改資料

    update 表名 set 列名1 = 值1, 列名2 = 值2...where 條件;

    注意:

    如果不加任何的條件,則會將表中的所有的記錄全部修改

查詢表中的記錄(DQL)

  • 查詢語法概述

    select 
    	-- 欄位列表
    from
    	-- 表名列表
    where
    	-- 條件列表
    group by
    	-- 分組欄位
    having
    	-- 分組之後的條件
    order by
    	-- 排序
    limit
    	-- 分頁限定
    
  • 基礎查詢

    1. 多個欄位查詢

      select 欄位名1, 欄位名2, ...from 表名

      注意:

      如果查詢所有的欄位,則可以使用*來代替欄位列表

      select * from 表名

    2. 去除重複

      select後加distinct

      注意:

      只有兩個得到的結果請求的各個欄位完全一樣才能去重複

    3. 計算列

      一般可以使用四則運算計算一些列的值(一般只會進行數值型的計算),

      若參與運算的欄位中有非數值型的資料(如果有null則預設的運算結果都是null)則對這個欄位使用:

      ifnull(表示式1, 表示式2)其中表達式1判斷指定欄位是否為null,表示式2表示若該欄位為null後的替換值

    4. 起別名

      欄位名+as+別名

      as可省略,用空格代替

    5. 基礎查詢示例Code

      SHOW databases;
      USE db1;
      SHOW TABLES;
      DESC student;
      
      TRUNCATE TABLE student;
      
      INSERT INTO student (id, name, score) VALUES(01, "Jeff", 75);
      INSERT INTO student (id, name, score) VALUES(02, "Kim", 84);
      INSERT INTO student (id, name, score) VALUES(03, "Mohammed", 96);
      INSERT INTO student (id, name, score) VALUES(04, "Tim", 65);
      INSERT INTO student (id, name, score) VALUES(05, "Kim", 86);
      SELECT * FROM student;
      SELECT DISTINCT name,id FROM student;
      SELECT name, id, score, id + score FROM student;
      SELECT *, id + score idScore, id + ifnull(birthdate, 0) AS total_id FROM student;
      
  • 條件查詢

    • 格式:where後跟條件(欄位+運算子)

    • 條件查詢相關的運算子

      • >, <, <= , >=, = , <>

        SQL中判斷相等用=

        <>作用同!=

      • between ... and...

        n bwtween a and b作用相當於n >= a && n <= b

      • in()

        n in (a, b, c)作用相當於n = a or n = b or n = c

      • like 模糊查詢

        • like中的佔位字元

          _單個任意字元

          %多個任意字元

        • 模糊查詢示例Code

          SELECT * FROM student WHERE name LIKE "_i%"; /*查詢名字中第二個字母是i的行*/
          SELECT * FROM student WHERE name LIKE "____";/*查詢名字中有四個字母組成的行*/
          SELECT * FROM student WHERE name LIKE "%m%";/*查詢名字裡包含m的行*/
          SELECT * FROM student WHERE name LIKE "J%";/*查詢名字首字母是J的行*/
          
      • is null

        判斷數值的條件可以用=,如果是null需要用is null來判斷

      • and , &&

      • or, ||

      • not, !

    • 條件查詢示例Code

      SHOW databases;
      USE db1;
      SHOW TABLES;
      DESC student;
      
      TRUNCATE TABLE student;
      
      INSERT INTO student (id, name, score) VALUES(01, "Jeff", 75);
      INSERT INTO student (id, name, score) VALUES(02, "Kim", 84);
      INSERT INTO student (id, name, score) VALUES(03, "Mohammed", 96);
      INSERT INTO student (id, name, score) VALUES(04, "Tim", 65);
      INSERT INTO student (id, name, score) VALUES(05, "Kim", 86);
      -- DELETE FROM student WHERE score = 65;
      SELECT * FROM student WHERE id > 2 and id < 4;
      SELECT * FROM student WHERE id > 2 and id < 4;
      SELECT * FROM student WHERE id BETWEEN 2 AND 4;
      SELECT * FROM student WHERE id = 1 OR id = 4 OR id = 5;
      SELECT * FROM student WHERE id IN (1, 3, 5);
      UPDATE student set score = null WHERE name = 'Jeff';
      SELECT * FROM student WHERE score IS NOT NULL;
      
  • 排序查詢

    • order by格式:

      order by 排序欄位1 排序方式1, 排序欄位2 排序方式2...

      多個欄位排序,當前面欄位的條件值一樣時,才會判斷後面的條件

    • 排序方式:

      ASC:升序(預設升序)

      DESC:降序

    • 排序查詢示例Code

      SELECT * FROM student ORDER BY id desc, score desc;
      
  • 聚合函式

    • 概述

      聚合函式是將一列資料作為一個整體,進行縱向的計算

      聚合函式的計算會排除null值, 可以使用ifnull()跳過排除

      聚合函式一般選擇非空的列(主鍵)

    • 聚合函式分類

      1. count計算個數

        count(*)表示表中包含所有的行數

      2. max計算最大值

      3. min計算最小值

      4. sum計算和

      5. avg計算平均值

    • 聚合函式示例Code

      SELECT max(score) FROM student;
      SELECT avg(score) FROM student;/*平均值按照非null的個數計算*/
      
      SELECT max(ifnull(score, 0)) FROM student;
      SELECT avg(ifnull(score, 0)) FROM student;/*平均值仍然按照總個數計算*/
      
  • 分組查詢

    • group by格式

      group by 分組欄位

    • 分組之後查詢的欄位(select後寫的欄位):分組欄位、聚合函式

    • wherehaving的區別

      1. where在分組之前進行限定,如果不滿足條件,則不參與分組,having在分組之後進行限定,如果不滿足條件,則不會被查詢出來
      2. where後不可以跟聚合函式,having可以進行聚合函式的判斷
    • 分組查詢示例Code

      SELECT * FROM student;
      

      #將分數大於80和不大於80的所有行分組(1為大於80, 0為不大於80)
      select score > 80, avg(score), count(id) from student group by score > 80;
      

      #先選出id大於1的行,再將分數大於80和不大於80的所有行分組
      select score > 80, avg(score), count(id) from student where id > 1 group by score > 80;
      

      #先選出id大於1的行,再將分數大於80和不大於80的所有行分組,最後選出兩組中行數大於2的一組
      select score > 80, avg(score), count(id) from student where id > 1 group by score > 80 having count(id) > 2;
      

      #效果同上  先選出id大於1的行,再將分數大於80和不大於80的所有行分組,最後選出兩組中行數大於2的一組
      #對聚合函式欄位進行起別名,方便檢視
      select score > 80, avg(score), count(id) as pcount from student where id > 1 group by score > 80 having pcount > 2;
      select score > 80, avg(score), count(id) pcount from student where id > 1 group by score > 80 having pcount > 2;
      

  • 分頁查詢

    • 格式

      limit 開始的索引,每頁查詢的條數;

    • 公式

      開始的索引 = (當前的頁碼-1)*每頁顯示的條數

    • 示例Code

      #每頁查詢3條資料,從索引0開始
      select * from student limit 0, 3;#第一頁,從索引0開始
      select * from student limit 3, 3;#第二頁,從索引3開始
      select * from student limit 6, 3;#第三頁,從索引6開始
      
    • limit關鍵字是MySQL獨有的關鍵字,在其他資料庫中分頁查詢的關鍵字是不同的

管理使用者,授權(DCL)

  • 管理使用者

    1. 新增使用者

      建立使用者格式:CREATE USER '使用者名稱'@'主機名' IDENTIFIED BY 密碼;

      主機名使用萬用字元%表示可以在任意主機使用使用者登入資料庫

    2. 刪除使用者

      刪除使用者格式:DROP USER '使用者名稱'@'主機名';

    3. 修改使用者密碼

      修改使用者密碼方式1:

      UPDATE USER SET PASSWORD = PASSWORD('新密碼') WHERE USER = '使用者名稱';

      修改使用者密碼方式2:

      SET PASSWORD FOR '使用者名稱'@'主機名' = PASSWORD('新密碼');

    4. MySQL中忘記了root使用者密碼,解決方案

      1. 使用cmd命令停止mysql服務

        net stop mysql

        需要管理員執行該cmd

      2. 使用無驗證方式啟動mysql服務: mysql --skip-grant-tables

      3. 再開啟一個新的cmd視窗,直接輸入mysql,回車就可以登入

      4. use mysql;

      5. update user set password = password('新密碼') where user = ‘root’;

      6. 關閉兩個視窗

      7. 開啟工作管理員,手動結束mysqld.exe的程序

      8. 啟動mysql服務

      9. 使用新密碼登入

    5. 查詢使用者

      步驟:

      1. 切換到MySQL資料庫

      2. 查詢user表

        萬用字元%表示可以在任意主機使用使用者登入資料庫

  • 授權

    1. 查詢許可權

      SHOW GRANTS FOR '使用者名稱'@'主機名';

    2. 授予許可權

      grant 許可權列表 on 資料庫名.表名 to '使用者名稱'@'主機名';

      許可權列表使用 all表示使用所有的許可權,資料庫和表名使用*.*表示使用所有的資料庫和所有的表

    3. 撤銷許可權

      revoke 許可權列表 on 資料庫名.表名 from '使用者名稱'@'主機名';

二、MySQL約束

約束概述

  • 約束是對錶中的資料進行限定,保證資料的正確性、有效性和完整性
  • 約束的分類:
    1. 主鍵約束:primary key
    2. 非空約束:not null
    3. 唯一約束:unique
    4. 外來鍵約束:foreign key

非空約束

  • 非空約束:某一列的值不能為null

  • 非空約束關鍵字:not null

  • 新增非空約束

    • 建立表時新增非空約束

      示例Code

      show DATABASES;
      use db1;
      show tables;
      
      CREATE TABLE stu(
      	id INT,
          name varchar(20) not null
      );
      
    • 建立完表後,新增非空約束

      示例Code

      show DATABASES;
      use db1;
      show tables;
      
      CREATE TABLE stu(
      	id INT,
          name varchar(20)
      );
      
      ALTER TABLE stu MODIFY name varchar(20) not null;#使用更改表中的欄位資料型別進行新增非空約束
      
      INSERT INTO stu VALUES(01, null);#ERROR
      
      select * from stu;
      
    • 刪除非空約束

      示例Code

      show DATABASES;
      use db1;
      show tables;
      
      CREATE TABLE stu(
      	id INT,
          name varchar(20) not null
      );
      
      ALTER TABLE stu MODIFY name varchar(20);#使用更改表中的欄位資料型別進行刪除非空約束
      

唯一約束

  • 唯一約束:某一列的值不能重複

    新增唯一約束後,欄位值可以是null,但不能再重複使用欄位值null

  • 唯一約束關鍵字:unique

  • 新增唯一約束

    • 建立表時,新增唯一約束

      示例Code

      show DATABASES;
      use db1;
      show tables;
      
      CREATE TABLE stu(
      	ID INT,
          PHONE_NUMBER varchar(20) UNIQUE
      );
      
      INSERT INTO stu VALUES(01, "8717");
      INSERT INTO stu VALUES(02, "8717");#ERROR
      
    • 建立表後,新增唯一約束

      示例Code

      show DATABASES;
      use db1;
      show tables;
      
      CREATE TABLE stu(
      	ID INT,
          PHONE_NUMBER VARCHAR(20)
      );
      
      #注意:先要刪除之前欄位值重複的行才能新增唯一約束
      ALTER TABLE stu MODIFY PHONE_NUMBER VARCHAR(20) UNIQUE;#使用更改欄位資料型別來新增唯一約束
      
      INSERT INTO stu VALUES(01, "8718");
      INSERT INTO stu VALUES(02, "8718");#ERROR
      
  • 刪除唯一約束

    • 使用DROP INDEX關鍵字

    • 示例Code

      show DATABASES;
      use db1;
      show tables;
      
      CREATE TABLE stu(
      	ID INT,
          PHONE_NUMBER VARCHAR(20) UNIQUE
      );
      
      ALTER TABLE stu MODIFY PHONE_NUMBER VARCHAR(20);#使用更改欄位資料型別的方法,無法刪除唯一約束
      ALTER TABLE stu DROP INDEX PHONE_NUMBER;#使用DROP INDEX關鍵字刪除唯一約束
      
      INSERT INTO stu VALUES(01, "8718");
      INSERT INTO stu VALUES(02, "8718");
      

主鍵約束

  • 主鍵約束:非空且唯一

    注意:

    1. 一張表只能有一個欄位為主鍵
    2. 主鍵就是表中記錄的唯一標識
  • 主鍵約束的關鍵字:primary key

  • 新增主鍵約束

    • 建立表時,新增主鍵

      示例Code

      show DATABASES;
      use db1;
      show tables;
      
      CREATE TABLE stu(
        ID INT PRIMARY KEY,
        PHONE_NUMBER VARCHAR(20)
      );
      
      INSERT INTO stu VALUES(01, "8718");
      INSERT INTO stu VALUES(01, "8718");#ERROR
      INSERT INTO stu VALUES(null, "8718");#ERROR
      
    • 建立表後,新增主鍵

      示例Code

      show DATABASES;
      use db1;
      show tables;
      
      CREATE TABLE stu(
      	ID INT PRIMARY KEY,
          PHONE_NUMBER VARCHAR(20)
      );
      
      #注意:先要刪除之前欄位值重複的行才能新增主鍵約束
      ALTER TABLE stu MODIFY ID INT PRIMARY KEY;
      
      INSERT INTO stu VALUES(01, "8718");
      INSERT INTO stu VALUES(01, "8718");#ERROR
      INSERT INTO stu VALUES(null, "8718");#ERROR
      
  • 刪除主鍵約束

    • 使用關鍵字DROP PRIMARY KEY

    • 示例Code

      show DATABASES;
      use db1;
      show tables;
      
      CREATE TABLE stu(
        ID INT PRIMARY KEY,
          PHONE_NUMBER VARCHAR(20)
      );
      
      ALTER TABLE stu MODIFY ID INT;#使用更改欄位資料型別無法刪除主鍵
      ALTER TABLE stu DROP PRIMARY KEY;#使用DROP PRIMARY KEY關鍵字刪除主鍵
      
      INSERT INTO stu VALUES(01, "8718");
      INSERT INTO stu VALUES(01, "8718");
      INSERT INTO stu VALUES(null, "8718");
      

自動增長

  • 自動增長經常與主鍵一起使用

  • 如果某一列是數值型別的,使用auto_increment可以來完成自動增長

  • 建立表時,新增自動增長:

    • 在主鍵約束後面新增自動增長關鍵字auto_increment
  • 示例Code

    ``` sql
    show DATABASES;
    use db1;
    

    show tables;

    CREATE TABLE stu(
      ID INT PRIMARY KEY AUTO_INCREMENT,
        PHONE_NUMBER VARCHAR(20)
    );
    
    INSERT INTO stu VALUES(01, "8718");
    INSERT INTO stu VALUES(111, "8718");
    #給主鍵約束後的欄位加AUTO_INCREMENT後,該欄位值可以是null,寫入的表的值是根據上一個int值的自增1後的結果
    INSERT INTO stu VALUES(null, "8718");
    ```
    
    • 案例演示:

      在欄位ID值為1和111後加入數個ID值為null的結果

  • 建立表後,新增和刪除自動增長

    • 使用更改欄位資料型別的方法新增和刪除自動增長,格式alter table 表名 modify 列名src 新資料型別;

    • 示例Code

      show DATABASES;
      use db1;
      show tables;
      
      CREATE TABLE stu(
      	ID INT PRIMARY KEY AUTO_INCREMENT,
          PHONE_NUMBER VARCHAR(20)
      );
      
      #建立表後,刪除自動增長,不用再寫一遍主鍵約束關鍵字
      ALTER TABLE	stu MODIFY ID INT;
      #建立表後,新增自動增長,不用再寫一遍主鍵約束關鍵字
      ALTER TABLE stu MODIFY ID INT AUTO_INCREMENT;
      
      INSERT INTO stu VALUES(01, "8718");
      INSERT INTO stu VALUES(111, "8718");
      INSERT INTO stu VALUES(null, "8718");
      

外來鍵約束

  • 外來鍵約束:讓表與表之間產生關係,從而保證資料的正確性

  • 外來鍵約束的關鍵字:foreign key

  • 建立表時新增外來鍵

    create table 表名(
    	
        ...
        外來鍵列
        constraint 外來鍵名稱 foreign key(外來鍵列名稱) references 主表名稱(主表列名稱)#constraint+外來鍵名稱,可以省略
    );
    
  • 建立表後新增外來鍵

    ALTER TABLE 表名 ADD CONSTRAINT 外來鍵名稱 FOREIGN KEY(外來鍵欄位名稱) REFERENCES 主表名稱(主表列名稱);
    
  • 刪除外來鍵

    ALTER TABLE 表名 DROP FOREIGN KEY 外來鍵名稱;
    
  • 級聯操作

    • 兩個表通過外來鍵約束,主表字段的值預設不能再更新或刪除,但是可以通過開啟級聯更新和級聯刪除來更改主表字段值同時和子表外來鍵欄位值同步

    • 級聯跟新

      ON UPDATE CASCADE

    • 級聯刪除

      ON DELETE CASCADE

    • 示例Code

      #同時開啟級聯跟新和級聯刪除
      ALTER TABLE 表名 ADD CONSTRAINT 外來鍵名稱 FOREIGN KEY(外來鍵欄位名稱) REFERENCES 主表名稱(主表列名稱) ON UPDATE CASCADE ON DELETE CASCADE;
      

三、MySQL多表

多表關係

  • 一對一

    舉例:人和身份證

    分析:一個人只有一個身份證,一個身份證只能對應一個人

    實現方式:

    一對一關係實現,可以在任意一方新增唯一外來鍵指向另一方的主鍵

    注意:一對一關係的情況通常會將兩張表合成一張表來使用,單純地實現一對一關係並不常見

  • 一對多(多對一)

    舉例:部門和員工

    分析:一個部門有多個員工,一個員工只能對應一個部門

    實現方式:在“多”的一方(員工表)建立外來鍵,指向“一”的一方(部門表)的主鍵

  • 多對多

    舉例:學生和課程

    分析:一個學生可以選擇很多門課程,一個課程也可以被很多學生選擇

    實現方式:多對多關係實現需要藉助第三張中間表,中間表至少包含兩個欄位,這兩個欄位作為第三張表的外來鍵,分別指向兩張表的主鍵

多表案例

  • 實現目標:旅遊網站中線路分類和線路之間的是一對多的關係,線路和使用者之間是多對多的關係

  • 示例Code

    SHOW DATABASES;
    USE db1;
    SHOW TABLES;
    
    #線路分類的表
    CREATE TABLE tab_category (
    	cid INT PRIMARY KEY AUTO_INCREMENT,
        cname VARCHAR(100) NOT NULL UNIQUE
    );
    
    #線路表
    CREATE TABLE tab_route (
    	rid INT PRIMARY KEY AUTO_INCREMENT,
        rname VARCHAR(100) NOT NULL UNIQUE,
        price DOUBLE,
        rdate DATE,
        cid INT,
        FOREIGN KEY (cid) REFERENCES tab_category(cid)
    );
    
    #使用者表
    CREATE TABLE tab_user (
    	uid INT PRIMARY KEY AUTO_INCREMENT,
        username VARCHAR(100) UNIQUE NOT NULL,
        birthdate DATE,
        telephone VARCHAR(11),
        email VARCHAR(100)
    );
    
    #使用者和線路的中間表
    CREATE TABLE tab_intermediate (
    	uid INT,
        rid INT,
        PRIMARY KEY(uid, rid),#聯合主鍵
        FOREIGN KEY (rid) REFERENCES tab_route(rid),
        FOREIGN KEY (uid) REFERENCES tab_user(uid)
    );
    

資料庫設計的正規化

  • 設計資料庫時, 需要遵循一些規範。要遵循後邊的正規化要求,必須先遵守前邊的所有的正規化要求

  • 三大正規化:

    • 第一正規化(1NF):每一列都是不可分割的原子資料項

    • 第二正規化(2NF):在1NF的基礎上,非主屬性必須完全依賴於碼(在1NF基礎上消除非主屬性對主碼的部分函式依賴)

      • 函式依賴:A->B,如果通過A屬性(屬性組)的值,可以確定唯一B屬性的值。則稱B依賴於A

        學號可以唯一確定學生姓名,所以姓名依賴於學號

        學號和課程名稱可以確定唯一的分數,所以分數依賴於學號和課程名稱這個屬性組

      • 完全函式依賴:A->B,如果A是一個屬性組,則B屬性值的確定,需要依賴於A屬性組中所有的屬性值

        (學號,課程名稱)->分數,分數依賴於學號和課程名稱這個屬性組

      • 部分函式依賴:A->B,如果A是一個屬性組,則B屬性值的確定,只需要依賴於A屬性組中的某一些值即可

        (學號,課程名稱)->學生姓名,學生姓名僅依賴於這個屬性組中的學號

      • 傳遞函式依賴:A->B,B->C,如果通過A屬性(屬性組)的值,可以確定唯一B屬性的值,在通過B屬性(屬性組)的值可以確定唯一C屬性的值,則稱C傳遞函式依賴於A

        學號->系名,系名->系主任

      • 碼:如果在一張表中,一個屬性或屬性組,被其他所有屬性所完全依賴,則稱這個屬性(屬性值)為該表的碼

        該表的碼是學號和課程名稱這個屬性組

      • 主屬性:碼屬性組中的所有屬性

      • 非主屬性:除過碼屬性組的屬性

    • 第三正規化(3NF):在2NF的基礎上,任何非主屬性不依賴於其他非主屬性(在2NF的基礎上消除傳遞依賴)

多表查詢

  • 笛卡爾積:有兩個集合A和B,取這兩個集合的所有的組合情況

    要完成多表查詢,需要消除無用的資料

  • 內連線查詢

    • 內連線查詢的思路:

      1. 從哪些表中查詢資料
      2. 查詢的條件
      3. 需要查詢的欄位

      顯式和隱式兩種內連線方式,使用的作用相同,只是格式不同

    • 隱式內連線

      • 使用where條件消除無用資料

      • 示例Code

        SHOW DATABASES;
        USE db1;
        SHOW TABLES;
        
        #建立部門表
        CREATE TABLE dept(
        	id INT PRIMARY KEY AUTO_INCREMENT,
            name VARCHAR(32)
        );
        
        #插入部門名稱資訊
        INSERT INTO dept(name) VALUES ('R&D'), ('marketing'), ('financial');
        SELECT * FROM dept;
        
        #建立員工表
        CREATE TABLE emp (
        	id INT PRIMARY KEY AUTO_INCREMENT,
            name VARCHAR(32),
            gender CHAR(1),
            salary DOUBLE,
            join_date DATE,
            dept_id INT,
            FOREIGN KEY (dept_id) REFERENCES dept (id)
        );
        
        #插入員工資訊
        INSERT INTO emp(name, gender, salary, join_date, dept_id) VALUES('Jeff', 'm', 5000, '2021-5-3', 01);
        INSERT INTO emp(name, gender, salary, join_date, dept_id) VALUES('Lucy', 'f', 4000, '2021-6-3', 02);
        
        SELECT * FROM emp;
        
        SELECT * FROM dept, emp;
        SELECT * FROM emp, dept;
        
        #使用隱式內連線進行查詢
        #------------------
        #不指定欄位查詢,顯示查詢到的子表和主表的所有欄位資訊
        SELECT * FROM dept, emp WHERE dept.id = emp.dept_id;
        #指定欄位查詢,顯示指定欄位的對應資訊
        SELECT dept.name, emp.name, emp.gender FROM dept, emp WHERE dept.id = emp.dept_id;
        
        #同樣是使用隱式內連線進行查詢
        #推薦格式:關鍵字換行寫+變數使用重新命名
        SELECT
        	t1.name,
            t2.name,
            t2.gender
        FROM
        	dept t1,
            emp  t2
        WHERE
        	t1.id = t2.dept_id;
        
    • 顯式內連線

      • 格式:

        select 欄位列表 from 表名1 inner join 表名2 on 條件

        inner可以省略

      • 示例Code

        #顯式內連線查詢結果同隱式內連線
        SELECT dept.name, emp.name, emp.gender FROM emp INNER JOIN dept ON dept.id = emp.dept_id;
        SELECT dept.name, emp.name, emp.gender FROM emp JOIN dept ON dept.id = emp.dept_id;
        
  • 外連線查詢

    • 外連線查詢的作用:若左表中存在外來鍵列的某一值為null的,使用內連線查詢無法查詢到值為null的那一行資訊,可以使用外連線來解決

    • 兩種外連線(左、右)方式,本質上是一樣的,交換左右表在查詢語句中的順序相當於是更換了左或右的連線方式

    • 左外連線

      • 查詢的是左表的所有資料+交集的部分(兩表的內連線)

      • 格式:

        select 欄位列表 from 表1(左表) left outer join 表2(右表) on 條件

        outer可以省略

    • 右外連線

      • 查詢的是右表的所有資料+交集的部分(兩表的內連線)

      • 格式:

        select 欄位列表 from 表1(左表) right outer join 表2(右表) on 條件

        outer可以省略

  • 子查詢

    • 子查詢:查詢中巢狀查詢,稱巢狀查詢為子查詢

    • 子查詢的結果是單行單列的

      子查詢的結果可以使用運算子去判斷

      可使用的運算子>, >=, =, <, <=

      #查詢員工表中工資最高的員工資訊
      SELECT * FROM emp WHERE emp.salary = (SELECT MAX(salary) FROM emp);
      
      #查詢員工表中小於平均工資的員工資訊
      SELECT * FROM emp WHERE emp.salary < (SELECT avg(salary) FROM emp);
      
    • 子查詢的結果是多行單列的

      子查詢的結果可以使用運算子去判斷

      可用的運算子in(xx,xx,xx)相當於xx or xx or

      #查詢部門表中指定的兩個部門id,查詢結果是一個多行單列的結果
      #SELECT id FROM dept WHERE name = 'R&D' OR name = 'marketing';
      #SELECT id FROM dept WHERE name in ('R&D', 'marketing');
      
      #查詢員工表中指定部門的員工資訊
      SELECT * FROM emp WHERE emp.dept_id in (SELECT id FROM dept WHERE name in ('R&D', 'marketing'));
      
    • 子查詢的結果是多行多列的

      子查詢可以作為一張虛擬表

      #查詢入職日期大於某個日期的員工表和部門表資訊
      SELECT * FROM emp, dept WHERE emp.dept_id = dept.id AND emp.join_date > '2021-5-5';
      
      #使用子查詢,將子查詢結果作為一張虛擬表
      #效果同上,查詢入職日期大於某個日期的員工表和部門表資訊
      SELECT * FROM (SELECT * FROM emp WHERE emp.join_date > '2021-5-5') t1, dept t2 WHERE t1.dept_id = t2.id;
      

四、MySQL事務

事務概述

  • 事務:

    如果一個包含多個步驟的業務操作,被事務管理,那麼這些操作要麼同時成功,要麼同時失敗

  • 事務提交的兩種方式:

    1. 自動提交

      一條DML語句會自動提交一次事務

      MySQL是自動提交的

    2. 手動提交

      需要先開啟事務,再提交

      Oracle資料庫是預設手動提交的

  • 檢視提交方式:

    SELECT @@autocommit;

    得到的結果1表示自動提交,0表示手動提交

  • 設定提交方式:

    SET @@autocommit = 0;設定為手動提交

  • 事務的操作:

    1. 開啟事務:start transaction

      使用開啟事務,對資料進行持久化更新,就要進行手動提交

    2. 回滾:rollback

    3. 提交:commit

      使用DML語句操作後,會自動提交,資料會持久化更新

  • 示例Code

    SHOW DATABASES;
    USE db2;
    SHOW TABLES;
    
    CREATE TABLE account(
    	id INT PRIMARY KEY AUTO_INCREMENT,
        name VARCHAR(32),
        balance DOUBLE
    );
    
    INSERT INTO account (name, balance) VALUES ('Jeff', 1000), ('George', 2000);
    
    SELECT * FROM account;
    
    #若同時執行開始事務語句和以下的兩條修改語句,只有在commit之後才能發生修改
    #中間發生錯誤,暫存的資料可手動使用rollback恢復
    START TRANSACTION;
    UPDATE account SET balance = balance - 500 WHERE name = 'Jeff';  
    AAA
    UPDATE account SET balance = balance + 500 WHERE name = 'George';
    
    COMMIT;
    ROLLBACK;
    

事務的四大特徵

  • 四大特徵:
    1. 原子性:是不可分割的最小操作單位,要麼同時成功,要麼同時失敗
    2. 永續性:當事務提交或回滾後,資料庫會持久化的儲存資料
    3. 隔離性:多個事務之間,相互獨立
    4. 一致性:事務操作前後,資料總量不變

事務的隔離級別

  • 事務隔離級別作用:多個事務之間是隔離的,相互獨立的,但是如果多個事務操作同一批資料,會引發一些問題,設定不同的隔離級別就可以解決這些問題

  • 存在的問題:

    1. 髒讀:一個事務,讀取到另一個事務中沒有提交的資料
    2. 不可重複讀(虛讀):在同一個事務中,兩次讀取到的資料不一樣
    3. 幻讀:一個事務操作(DML)資料表中所有記錄,另一個事務添加了一條資料,則第一個事務查詢不到自己的修改
  • 隔離級別:

    1. read uncommitted:讀未提交

      產生問題:髒讀、不可重複讀、幻讀

    2. read committed:讀已提交(Oracle預設)

      產生問題:不可重複讀、幻讀

    3. repeatable read:可重複讀(MySQL預設)

      產生問題:幻讀

      可以解決虛讀的問題,在兩邊的事務都提交的情況下才會,兩次讀到不一樣的資料

    4. serializable:序列化

      可以解決所有的問題

      一個事務操作資料表,另一個數據不可以操作這個資料表,只有當鎖開啟後才能操作

    注意:隔離級別從小到大安全性越來越高,但是效率額越來越低

  • 資料庫查詢和設定隔離級別:

    查詢隔離級別

    select @@tx_isolation;

    設定隔離級別

    set global transaction isolation level 級別字串;