1. 程式人生 > 其它 >09、操作資料庫的神器,SQL語言

09、操作資料庫的神器,SQL語言

1、SQL簡介

對資料庫進行查詢和修改操作的語言叫做 SQL(Structured Query Language,結構化查詢語言)。SQL 語言是目前廣泛使用的關係資料庫標準語言,是各種資料庫互動方式的基礎。著名的大型商用資料庫 Oracle、DB2、Sybase、SQL Server,開源的資料庫 PostgreSQL、MySQL,甚至一些小型的資料庫 Access 等都支援 SQL。近些年蓬勃發展的 NoSQL 系統最初是宣稱不再需要 SQL 的,後來也不得不修正為 Not Only SQL,來擁抱 SQL。

1、SQL是什麼

SQL 是一種資料庫查詢和程式設計語言,用於存取資料以及查詢、更新和管理關係資料庫系統。與其他程式設計語言(如 C語言、Java 等)不同的是,SQL 由很少的關鍵字組成,每個 SQL 語句通過一個或多個關鍵字構成。

  • SQL 具有如下優點:
    1. 一體化:SQL 集資料定義、資料操作和資料控制於一體,可以完成資料庫中的全部工作。
    2. 使用方式靈活:SQL 具有兩種使用方式,可以直接以命令方式互動使用;也可以嵌入使用,嵌入C、C++、Fortran、COBOL、Java 等語言中使用。
    3. 非過程化:只提操作要求,不必描述操作步驟,也不需要導航。使用時只需要告訴計算機“做什麼”,而不需要告訴它“怎麼做”,儲存路徑的選擇和操作的執行由資料庫管理系統自動完成。
    4. 語言簡潔、語法簡單:該語言的語句都是由描述性很強的英語單片語成,而且這些單詞的數目不多。

1)資料定義語言(Data Definition Language,DDL)

用來建立或刪除資料庫以及表等物件,主要包含以下幾種命令:

  • DROP:刪除資料庫和表等物件
  • CREATE:建立資料庫和表等物件
  • ALTER:修改資料庫和表等物件的結構

2)資料操作語言(Data Manipulation Language,DML)

用來變更表中的記錄,主要包含以下幾種命令:

  • SELECT:查詢表中的資料
  • INSERT:向表中插入新資料
  • UPDATE:更新表中的資料
  • DELETE:刪除表中的資料

3)資料查詢語言(Data Query Language,DQL)

用來查詢表中的記錄,主要包含 SELECT 命令,來查詢表中的資料。

4)資料控制語言(Data Control Language,DCL)

用來確認或者取消對資料庫中的資料進行的變更。除此之外,還可以對資料庫中的使用者設定許可權。主要包含以下幾種命令:

  • GRANT:賦予使用者操作許可權
  • REVOKE:取消使用者的操作許可權
  • COMMIT:確認對資料庫中的資料進行的變更
  • ROLLBACK:取消對資料庫中的資料進行的變更

標準 SQL 是指符合國際標準的 SQL,而非某個資料庫廠商的 SQL 語法(如:Microsoft SQL Server 的 T-SQL,Oracle 的 PL/SQL,MySQL)。
標準 SQL 可以在任何資料庫中使用,而資料庫廠商的 SQL 只適合它們對應的資料庫,如 T-SQL 只適合 Microsoft SQL Server。

2、SQL的基本規則

對於 SQL 初學者,在寫 SQL 語句時,只要遵守下面幾個書寫規則,就可以避免很多錯誤。這些規則都非常簡單,下面我們來逐一介紹。

1)SQL 語句要以分號(;)或\G結尾

在 RDBMS (關係型資料庫)當中,SQL 語句是逐條執行的,一條 SQL 語句代表著資料庫的一個操作。我們通常在句子的句尾加註標點表示這句話結束,中文句子以句號。結尾,英文以點號.結尾,而 SQL 語句則使用英文分號;結尾。

2)SQL 語句不區分大小寫

SQL 不區分關鍵字的大小寫。例如,不管寫成 SELECT 還是 select,解釋都是一樣的。表名和列名也是如此。

提示:關鍵字是資料庫事先定義的,有特別意義的單詞。

雖然可以根據個人喜好選擇大寫還是小寫(或大小寫混雜),但為了理解起來更加容易。

  • 關鍵字大寫
  • 資料庫名、表名和列名等小寫


需要注意的是,插入到表中的資料是區分大小寫的。例如,向資料庫中插入單詞 Computer、COMPUTER 或 computer,這三個是不一樣的資料。

3)SQL的註釋

SQL語言的註釋是:--

mysql> -- show databases;
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

2、MySQL資料庫

在SQL語言中,資料庫相當於資料夾。

1、檢視資料庫

  • 檢視所有資料庫
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
7 rows in set (0.00 sec)

mysql> 
  • 檢視資料庫定義
mysql> show create database test01;
+----------+-------------------------------------------------------------------+
| Database | Create Database                                                   |
+----------+-------------------------------------------------------------------+
| test01   | CREATE DATABASE `test01` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+-------------------------------------------------------------------+
1 row in set (0.00 sec)
  • 檢視正在使用的資料庫
mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select database();
+------------+
| database() |
+------------+
| mysql      |
+------------+
1 row in set (0.00 sec)

2、建立資料庫

  • 釋義
    • <資料庫名>:建立資料庫的名稱。MySQL 的資料儲存區將以目錄方式表示 MySQL 資料庫,因此資料庫名稱必須符合作業系統的資料夾命名規則,不能以數字開頭,儘量要有實際意義。注意在 MySQL 中不區分大小寫。
    • IF NOT EXISTS:在建立資料庫之前進行判斷,只有該資料庫目前尚不存在時才能執行操作。此選項可以用來避免資料庫已經存在而重複建立的錯誤。
    • [DEFAULT] CHARACTER SET:指定資料庫的字符集。指定字符集的目的是為了避免在資料庫中儲存的資料出現亂碼的情況。如果在建立資料庫時不指定字符集,那麼就使用系統的預設字符集。
    • [DEFAULT] COLLATE:指定字符集的預設校對規則。

  • 格式
CREATE DATABASE [IF NOT EXISTS] <資料庫名>
    [[DEFAULT] CHARACTER SET <字符集名>] 
    [[DEFAULT] COLLATE <校對規則名>];
  • 案例
mysql> CREATE DATABASE IF NOT EXISTS test01 CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| mysql              |
| performance_schema |
| sys                |
| test               |
| test01             |
+--------------------+
7 rows in set (0.00 sec)

3、修改資料庫

在 MySQL 資料庫中只能對資料庫使用的字符集和校對規則進行修改,資料庫的這些特性都儲存在 db.opt 檔案中。下面我們來介紹一下修改資料庫的基本操作。

注:字符集和校驗規則是儲存資料庫的一種方式。

在 MySQL 中,可以使用 ALTER DATABASE 來修改已經被建立或者存在的資料庫的相關引數。修改資料庫的語法格式為:

ALTER DATABASE [資料庫名] { 
[ DEFAULT ] CHARACTER SET <字符集名> |
[ DEFAULT ] COLLATE <校對規則名>}
  • 語法說明如下:
    • ALTER DATABASE 用於更改資料庫的全域性特性。
    • 使用 ALTER DATABASE 需要獲得資料庫 ALTER 許可權。
    • 資料庫名稱可以忽略,此時語句對應於預設資料庫(最新指定資料庫)。
    • CHARACTER SET 子句用於更改預設的資料庫字符集。
  • 案例
mysql> show create database test01;
+----------+-------------------------------------------------------------------+
| Database | Create Database                                                   |
+----------+-------------------------------------------------------------------+
| test01   | CREATE DATABASE `test01` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+-------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> ALTER DATABASE test01 
    -> DEFAULT CHARACTER SET utf8 
    -> DEFAULT COLLATE utf8_general_ci;
Query OK, 1 row affected (0.00 sec)

mysql> show create database test01;
+----------+-----------------------------------------------------------------+
| Database | Create Database                                                 |
+----------+-----------------------------------------------------------------+
| test01   | CREATE DATABASE `test01` /*!40100 DEFAULT CHARACTER SET utf8 */ |
+----------+-----------------------------------------------------------------+
1 row in set (0.00 sec)

4、指定資料庫

在 MySQL 中就有很多系統自帶的資料庫,那麼在操作資料庫之前就必須要確定是哪一個資料庫。在 MySQL 中,USE 語句用來完成一個數據庫到另一個數據庫的跳轉。

當用 CREATE DATABASE 語句建立資料庫之後,該資料庫不會自動成為當前資料庫,需要用 USE 來指定當前資料庫。其語法格式為:

USE [資料庫名稱];

注:該語句可以通知 MySQL 把<資料庫名>所指示的資料庫作為當前資料庫。該資料庫保持為預設資料庫,直到語段的結尾,或者直到遇見一個不同的 USE 語句。 只有使用 USE 語句來指定某個資料庫作為當前資料庫之後,才能對該資料庫及其儲存的資料物件執行操作。
  • 案例
mysql> use test01;
Database changed
mysql> 

5、刪除資料庫

當資料庫不再使用時應該將其刪除,以確保資料庫儲存空間中存放的是有效資料。刪除資料庫是將已經存在的資料庫從磁碟空間上清除,清除之後,資料庫中的所有資料也將一同被刪除。

在 MySQL 中,當需要刪除已建立的資料庫時,可以使用 DROP DATABASE 語句。其語法格式為:

DROP DATABASE [ IF EXISTS ] <資料庫名>
  • 語法說明如下:
    • <資料庫名>:指定要刪除的資料庫名。
    • IF EXISTS:用於防止當資料庫不存在時發生錯誤。
    • DROP DATABASE:刪除資料庫中的所有表格並同時刪除資料庫。使用此語句時要非常小心,以免錯誤刪除。如果要使用 DROP DATABASE,需要獲得資料庫 DROP 許可權。

  • 案例
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| mysql              |
| performance_schema |
| sys                |
| test               |
| test01             |
+--------------------+
7 rows in set (0.00 sec)

mysql> drop database test01;
Query OK, 0 rows affected (0.03 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| db1                |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
6 rows in set (0.00 sec)

注意:MySQL 安裝後,系統會自動建立名為 information_schema 和 mysql 的兩個系統資料庫,系統資料庫存放一些和資料庫相關的資訊,如果刪除了這兩個資料庫,MySQL 將不能正常工作。

6、資料庫註釋

1) 單行註釋可以使用#註釋符,#註釋符後直接加註釋內容。格式如下:

#註釋內容
單行註釋使用註釋符#的示例如下:
#從結果中刪除重複行
SELECT DISTINCT product_id, purchase_price FROM Product;


2) 單行註釋可以使用--註釋符,--註釋符後需要加一個空格,註釋才能生效。格式如下:

-- 註釋內容
單行註釋使用註釋符--的示例如下:
-- 從結果中刪除重複行
SELECT DISTINCT product_id, purchase_price FROM Product;

#和--的區別就是:#後面直接加註釋內容,而--的第 2 個破折號後需要跟一個空格符在加註釋內容。

3) MySQL 多行註釋

多行註釋使用/* */註釋符。/*用於註釋內容的開頭,*/用於註釋內容的結尾。多行註釋格式如下:

/*
第一行註釋內容
第二行註釋內容
*/

註釋內容寫在/*和*/之間,可以跨多行。

3、Mysql資料中的資料型別

資料型別(data_type)是指系統中所允許的資料的型別。MySQL 資料型別定義了列中可以儲存什麼資料以及該資料怎樣儲存的規則。

資料庫中的每個列都應該有適當的資料型別,用於限制或允許該列中儲存的資料。例如,列中儲存的為數字,則相應的資料型別應該為數值型別。

如果使用錯誤的資料型別可能會嚴重影響應用程式的功能和效能,所以在設計表時,應該特別重視資料列所用的資料型別。更改包含資料的列不是一件小事,這樣做可能會導致資料丟失。因此,在建立表時必須為每個列設定正確的資料型別和長度。

MySQL 的資料型別有大概可以分為 5 種,分別是整數型別、浮點數型別和定點數型別、日期和時間型別、字串型別、二進位制型別等。

1、MySQL整數型別

整數型別又稱數值型資料,數值型資料型別主要用來儲存數字。

MySQL 提供了多種數值型資料型別,不同的資料型別提供不同的取值範圍,可以儲存的值範圍越大,所需的儲存空間也會越大。

MySQL 主要提供的整數型別有 TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,其屬性欄位可以新增 AUTO_INCREMENT 自增約束條件。下表中列出了 MySQL 中的數值型別。

型別名稱

說明

儲存需求

TINYINT

很小的整數

1個位元組

SMALLINT

小的整數

2個宇節

MEDIUMINT

中等大小的整數

3個位元組

INT (INTEGHR)

普通大小的整數

4個位元組

BIGINT

大整數

8個位元組

從上表中可以看到,不同型別的整數儲存所需的位元組數不相同,佔用位元組數最小的是 TINYINT 型別,佔用位元組最大的是 BIGINT 型別,佔用的位元組越多的型別所能表示的數值範圍越大。

根據佔用位元組數可以求出每一種資料型別的取值範圍。例如,TINYINT 需要 1 個位元組(8bit)來儲存,那麼 TINYINT 無符號數的最大值為 28-1,即 255;TINYINT 有符號數的最大值為 27-1,即 127。其他型別的整數的取值範圍計算方法相同,如下表所示。

型別名稱

說明

儲存需求

TINYINT

-128〜127

0 〜255

SMALLINT

-32768〜32767

0〜65535

MEDIUMINT

-8388608〜8388607

0〜16777215

INT (INTEGER)

-2147483648〜2147483647

0〜4294967295

BIGINT

-9223372036854775808〜9223372036854775807

0〜18446744073709551615

  • 案例
用utf8mb4建立xiaowu庫
mysql> create database xiaowu charset utf8mb4;
使用xiaowu庫;
mysql> use xiaowu;
在xiaowu庫下建立t1表,id列用int型,name列用varchar型,age用tinyint型
mysql> create table t1(id int ,name varchar(64) ,age tinyint);

說明:手機號是無法儲存到int的。一般是使用char型別來儲存手機


2、MySQL小數型別

MySQL 中使用浮點數和定點數來表示小數。

浮點型別有兩種,分別是單精度浮點數(FLOAT)和雙精度浮點數(DOUBLE);定點型別只有一種,就是 DECIMAL。

浮點型別和定點型別都可以用(M, D)來表示,其中M稱為精度,表示總共的位數;D稱為標度,表示小數的位數。

浮點數型別的取值範圍為 M(1~255)和 D(1~30,且不能大於 M-2),分別表示顯示寬度和小數位數。M 和 D 在 FLOAT 和DOUBLE 中是可選的,FLOAT 和 DOUBLE 型別將被儲存為硬體所支援的最大精度。DECIMAL 的預設 D 值為 0、M 值為 10。

下表中列出了 MySQL 中的小數型別和儲存需求。

型別名稱

說明

儲存需求

FLOAT

單精度浮點數

4 個位元組

DOUBLE

雙精度浮點數

8 個位元組

DECIMAL (M, D)

壓縮的“嚴格”定點數

M+2 個位元組

DECIMAL 型別不同於 FLOAT 和 DOUBLE。DOUBLE 實際上是以字串的形式存放的,DECIMAL 可能的最大取值範圍與 DOUBLE 相同,但是有效的取值範圍由 M 和 D 決定。如果改變 M 而固定 D,則取值範圍將隨 M 的變大而變大。

從上表中可以看到,DECIMAL 的儲存空間並不是固定的,而由精度值 M 決定,佔用 M+2 個位元組。

FLOAT 型別的取值範圍如下:

  • 有符號的取值範圍:-3.402823466E+38~-1.175494351E-38。
  • 無符號的取值範圍:0 和 -1.175494351E-38~-3.402823466E+38。


DOUBLE 型別的取值範圍如下:

  • 有符號的取值範圍:-1.7976931348623157E+308~-2.2250738585072014E-308。
  • 無符號的取值範圍:0 和 -2.2250738585072014E-308~-1.7976931348623157E+308。

3、MySQL字串型別

字串型別用來儲存字串資料,還可以儲存圖片和聲音的二進位制資料。字串可以區分或者不區分大小寫的串比較,還可以進行正則表示式的匹配查詢。

MySQL 中的字串型別有 CHAR、VARCHAR、TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT、ENUM、SET 等。

下表中列出了 MySQL 中的字串資料型別,括號中的M表示可以為其指定長度。

型別名稱

說明

儲存需求

CHAR(M)

固定長度非二進位制字串

M 位元組,1<=M<=255

VARCHAR(M)

變長非二進位制字串

L+1位元組,在此,L< = M和 1<=M<=255

TINYTEXT

非常小的非二進位制字串

L+1位元組,在此,L<2^8

TEXT

小的非二進位制字串

L+2位元組,在此,L<2^16

MEDIUMTEXT

中等大小的非二進位制字串

L+3位元組,在此,L<2^24

LONGTEXT

大的非二進位制字串

L+4位元組,在此,L<2^32

ENUM

列舉型別,只能有一個列舉字串值

1或2個位元組,取決於列舉值的數目 (最大值為65535)

VARCHAR 和 TEXT 型別是變長型別,其儲存需求取決於列值的實際長度(在前面的表格中用 L 表示),而不是取決於型別的最大可能尺寸。

例如,一個 VARCHAR(10) 列能儲存一個最大長度為 10 個字元的字串,實際的儲存需要字串的長度 L 加上一個位元組以記錄字串的長度。對於字元 “abcd”,L 是 4,而儲存要求 5 個位元組。

mysql> CREATE TABLE test05 (
    -> name VARCHAR(255)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE test06( name ENUM("1","2","3") );
Query OK, 0 rows affected (0.01 sec)


4、MySQL日期和時間型別

MySQL 中有多處表示日期的資料型別:YEAR、TIME、DATE、DTAETIME、TIMESTAMP。當只記錄年資訊的時候,可以只使用 YEAR 型別。

每一個型別都有合法的取值範圍,當指定確定不合法的值時,系統將“零”值插入資料庫中。

下表中列出了 MySQL 中的日期與時間型別。

型別名稱

日期格式

日期範圍

儲存需求

YEAR

YYYY

1901 ~ 2155

1 個位元組

TIME

HH:MM:SS

-838:59:59 ~ 838:59:59

3 個位元組

DATE

YYYY-MM-DD

1000-01-01 ~ 9999-12-3

3 個位元組

DATETIME

YYYY-MM-DD HH:MM:SS

1000-01-01 00:00:00 ~ 9999-12-31 23:59:59

8 個位元組

TIMESTAMP

YYYY-MM-DD HH:MM:SS

1980-01-01 00:00:01 UTC ~ 2040-01-19 03:14:07 UTC

4 個位元組

  • 案例
mysql> create database db1 charset utf8;
Query OK, 1 row affected (0.03 sec)

mysql> use db1;
Database changed

mysql> create table t1(id int,name char, date1 date, date2 time, date3 datetime, date4 timestamp, date5 year);
Query OK, 0 rows affected (0.05 sec)

mysql> insert into t1 values (1, '1', '2021-09-09','12:12:12','2021-09-09','2021-09-09','2021');
Query OK, 1 row affected (0.04 sec)

mysql> select * from t1;
+----+------+------------+----------+---------------------+---------------------+-------+
| id | name | date1      | date2    | date3               | date4               | date5 |
+----+------+------------+----------+---------------------+---------------------+-------+
|  1 | 1    | 2021-09-09 | 12:12:12 | 2021-09-09 00:00:00 | 2021-09-09 00:00:00 |  2021 |
+----+------+------------+----------+---------------------+---------------------+-------+
1 row in set (0.07 sec)


datetime 和 timestamp 之間的區別?
    
  1、兩者的儲存方式不一樣
    對於TIMESTAMP,它把客戶端插入的時間從當前時區轉化為UTC(世界標準時間)進行儲存。查詢時,將其又轉化為客戶端當前時區進行返回。
    對於DATETIME,不做任何改變,基本上是原樣輸入和輸出。
    
  2、兩者所能儲存的時間範圍不一樣
    timestamp所能儲存的時間範圍為:‘1970-01-01 00:00:01.000000’ 到 ‘2038-01-19 03:14:07.999999’。
    datetime所能儲存的時間範圍為:‘1000-01-01 00:00:00.000000’ 到 ‘9999-12-31 23:59:59.999999’。
    
    mysql> insert into t1 values (1, '1', '2021-09-09','12:12:12','2221-09-09 12','2221-09-09','2021');
        1292 - Incorrect datetime value: '2221-09-09' for column 'date4' at row 1

5、MySQL二進位制型別

MySQL 中的二進位制字串有 BIT、BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。

下表中列出了 MySQL 中的二進位制資料型別,括號中的M表示可以為其指定長度。

型別名稱

說明

儲存需求

BIT(M)

位欄位型別

大約 (M+7)/8 位元組

BINARY(M)

固定長度二進位制字串

M 位元組

VARBINARY (M)

可變長度二進位制字串

M+1 位元組

TINYBLOB (M)

非常小的BLOB

L+1 位元組,在此,L<2^8

BLOB (M)

小 BLOB

L+2 位元組,在此,L<2^16

MEDIUMBLOB (M)

中等大小的BLOB

L+3 位元組,在此,L<2^24

LONGBLOB (M)

非常大的BLOB

L+4 位元組,在此,L<2^32

  • 案例
import pymysql

class BlobDataTestor:
    def __init__(self):
        self.conn = pymysql.connect(host='127.0.0.1', user='root', passwd='123456', db='db1', port=3306)

    def __del__(self):
        try:
            self.conn.close()
        except:
            pass

    def closedb(self):
        self.conn.close()

    def setup(self):
        cursor = self.conn.cursor()
        cursor.execute("""  
             CREATE TABLE IF NOT EXISTS `Dem_Picture` (  
             `ID` int(11) NOT NULL auto_increment,  
             `PicData` mediumblob,  
             PRIMARY KEY (`ID`)  
             ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;  
             """)


    def testRWBlobData(self):
        # 讀取源圖片資料
        f = open("D:\\1.jpg", "rb")
        b = f.read()
        f.close()

        # 將圖片資料寫入表
        cursor = self.conn.cursor()
        cursor.execute("INSERT INTO Dem_Picture (PicData) VALUES (%s)", (pymysql.Binary(b)))
        # self.conn.commit()

        # 讀取表內圖片資料,並寫入硬碟檔案
        cursor.execute("SELECT PicData FROM Dem_Picture ORDER BY ID DESC limit 1")
        d = cursor.fetchone()[0]
        cursor.close()

        f = open("D:\\1.jpg", "wb")
        f.write(d)
        f.close()


# 下面一句的作用是:執行本程式檔案時執行什麼操作  
if __name__ == "__main__":

    test = BlobDataTestor()

    try:
        test.setup()
        test.testRWBlobData()
        # test.teardown()
    finally:
        test.closedb()


6、MySQL系統變數

在 MySQL 資料庫,變數分為系統變數和使用者自定義變數。系統變數以 @@ 開頭,使用者自定義變數以 @ 開頭。

伺服器維護著兩種系統變數,即全域性變數(GLOBAL VARIABLES)和會話變數(SESSION VARIABLES)。全域性變數影響 MySQL 服務的整體執行方式,會話變數影響具體客戶端連線的操作。

每一個客戶端成功連線伺服器後,都會產生與之對應的會話。會話期間,MySQL 服務例項會在伺服器記憶體中生成與該會話對應的會話變數,這些會話變數的初始值是全域性變數值的拷貝。

1、檢視系統變數

可以使用以下命令檢視 MySQL 中所有的全域性變數資訊。

SHOW GLOBAL VARIABLES; 

可以使用以下命令檢視與當前會話相關的所有會話變數以及全域性變數。

SHOW SESSION VARIABLES;

其中,SESSION 關鍵字可以省略。

4、MySQL資料表

資料表是資料庫的重要組成部分,每一個數據庫都是由若干個資料表組成的。換句話說,沒有資料表就無法在資料庫中存放資料。

1、建立資料表

在建立資料庫之後,接下來就要在資料庫中建立資料表。所謂建立資料表,指的是在已經建立的資料庫中建立新表。

建立資料表的過程是規定資料列的屬性的過程,同時也是實施資料完整性(包括實體完整性、引用完整性和域完整性)約束的過程。接下來我們介紹一下建立資料表的語法形式。

1、基本語法

在 MySQL 中,可以使用 CREATE TABLE 語句建立表。其語法格式為:

CREATE TABLE <表名> ([表定義選項])[表選項][分割槽選項];

其中,[表定義選項]的格式為:

<列名1> <型別1> [,…] <列名n> <型別n>

CREATE TABLE 命令語法比較多,其主要是由表建立定義(create-definition)、表選項(table-options)和分割槽選項(partition-options)所組成的。

這裡首先描述一個簡單的新建表的例子,然後重點介紹 CREATE TABLE 命令中的一些主要的語法知識點。

CREATE TABLE 語句的主要語法及使用說明如下:

  • CREATE TABLE:用於建立給定名稱的表,必須擁有表CREATE的許可權。
  • <表名>:指定要建立表的名稱,在 CREATE TABLE 之後給出,必須符合識別符號命名規則。表名稱被指定為 db_name.tbl_name,以便在特定的資料庫中建立表。無論是否有當前資料庫,都可以通過這種方式建立。在當前資料庫中建立表時,可以省略 db-name。如果使用加引號的識別名,則應對資料庫和表名稱分別加引號。例如,'mydb'.'mytbl' 是合法的,但 'mydb.mytbl' 不合法。
  • <表定義選項>:表建立定義,由列名(col_name)、列的定義(column_definition)以及可能的空值說明、完整性約束或表索引組成。
  • 預設的情況是,表被建立到當前的資料庫中。若表已存在、沒有當前資料庫或者資料庫不存在,則會出現錯誤。

2、建立資料表

資料表屬於資料庫,在建立資料表之前,應使用語句“USE<資料庫>”指定操作在哪個資料庫中進行,如果沒有選擇資料庫,就會丟擲 No database selected 的錯誤。

mysql> CREATE TABLE test01(
    -> id int(11),
    -> name VARCHAR(25)
    -> );
Query OK, 0 rows affected (0.02 sec)

語句執行後,便建立了一個名稱為 test01 的資料表,使用 SHOW TABLES;語句檢視資料表是否建立成功,如下所示。

mysql> SHOW TABLES;
+---------------+
| Tables_in_db1 |
+---------------+
| test01        |
+---------------+
2 rows in set (0.00 sec)

2、修改資料表

修改資料表的前提是資料庫中已經存在該表。修改表指的是修改資料庫中已經存在的資料表的結構。修改資料表的操作也是資料庫管理中必不可少的,就像畫素描一樣,畫多了可以用橡皮擦掉,畫少了可以用筆加上。

不瞭解如何修改資料表,就相當於是我們只要畫錯了就要扔掉重畫,這樣就增加了不必要的成本。

1、修改表名

MySQL 通過 ALTER TABLE 語句來實現表名的修改。

ALTER TABLE <舊錶名> RENAME [TO] <新表名>;
  • 案例
mysql> ALTER TABLE test01 RENAME TO test_01;
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW TABLES;
+---------------+
| Tables_in_db1 |
+---------------+
| Dem_Picture   |
| test_01       |
+---------------+
2 rows in set (0.00 sec)

2、修改表字符集

MySQL 通過 ALTER TABLE 語句來實現表字符集的修改。

ALTER TABLE 表名 [DEFAULT] CHARACTER SET <字符集名> [DEFAULT] COLLATE <校對規則名>;

其中,DEFAULT 為可選引數,使用與否均不影響結果。

mysql> SHOW CREATE TABLE test_01\G
*************************** 1. row ***************************
       Table: test_01
Create Table: CREATE TABLE `test_01` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(25) CHARACTER SET utf8 DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=gb2312
1 row in set (0.00 sec)

3、修改表字段


在 MySQL 中可以使用 ALTER TABLE 語句來改變原有表的結構,例如增加或刪減列、更改原有列型別、重新命名列或表等。

其語法格式如下:

ALTER TABLE <表名> CHANGE <舊欄位名> <新欄位名> <新資料型別>;
  • 案例
mysql> ALTER TABLE test_01 CHANGE name  name CHAR(11);
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC test_01;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(11)  | YES  |     | NULL    |       |
| name  | char(11) | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

4、修改欄位資料型別

修改欄位的資料型別就是把欄位的資料型別轉換成另一種資料型別。

ALTER TABLE <表名> MODIFY <欄位名> <資料型別>

其中:

  • 表名:指要修改資料型別的欄位所在表的名稱;
  • 欄位名:指需要修改的欄位;
  • 資料型別:指修改後欄位的新資料型別。

案例

mysql> DESC test_01;
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(11)  | YES  |     | NULL    |       |
| name  | char(11) | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> ALTER TABLE test_01 MODIFY name VARCHAR(15);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC test_01;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(15) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

3、刪除資料表

在 MySQL 資料庫中,對於不再需要的資料表,我們可以將其從資料庫中刪除。

在刪除表的同時,表的結構和表中所有的資料都會被刪除,因此在刪除資料表之前最好先備份,以免造成無法挽回的損失。

下面我們來了解一下 MySQL 資料庫中資料表的刪除方法。

1、基礎語法

使用 DROP TABLE 語句可以刪除一個或多個數據表,語法格式如下:

DROP TABLE [IF EXISTS] 表名1 [ ,表名2, 表名3 ...]

對語法格式的說明如下:

  • 表名1, 表名2, 表名3 ...表示要被刪除的資料表的名稱。DROP TABLE 可以同時刪除多個表,只要將表名依次寫在後面,相互之間用逗號隔開即可。
  • IF EXISTS 用於在刪除資料表之前判斷該表是否存在。如果不加 IF EXISTS,當資料表不存在時 MySQL 將提示錯誤,中斷 SQL 語句的執行;加上 IF EXISTS 後,當資料表不存在時 SQL 語句可以順利執行,但是會發出警告(warning)。


兩點注意:

  • 使用者必須擁有執行 DROP TABLE 命令的許可權,否則資料表不會被刪除。
  • 表被刪除時,使用者在該表上的許可權不會自動刪除。

2、刪除資料表

刪除資料表test_01。

mysql> DROP TABLE test_01;
Query OK, 0 rows affected (0.00 sec)

3、刪除欄位

刪除欄位是將資料表中的某個欄位從表中移除。

ALTER TABLE <表名> DROP <欄位名>;
  • 案例
mysql> DESC db01;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int(11)      | NO   | PRI | NULL    | auto_increment |
| name  | varchar(255) | YES  |     | NULL    |                |
+-------+--------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> ALTER TABLE db01 DROP name;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC db01;
+-------+---------+------+-----+---------+----------------+
| Field | Type    | Null | Key | Default | Extra          |
+-------+---------+------+-----+---------+----------------+
| id    | int(11) | NO   | PRI | NULL    | auto_increment |
+-------+---------+------+-----+---------+----------------+
1 row in set (0.00 sec)

4、表資料的增刪改查

表相當於檔案,表中儲存的其實是真正的資料。如下我們介紹一下表資料的各種常見操作。

1、增加表資料

增加資料其實就是向表中插入資料,或者是向表中新增資料。

格式:

INSERT INTO <表名> (欄位1,欄位2,...欄位n) VALUES (資料1,資料2...資料n);

案例:

-- 建立一個班級表
CREATE TABLE class(
    id int,
  name varchar(50),
  age tinyint(2),
  sex enum('1','2')
);

-- 向班級中插入資料
INSERT INTO class (id,name,age,sex) VALUES (1,'班長',18,1);
INSERT INTO class (id,name,age,sex) VALUES (2,'小仙女',16,2);

測試結果:

mysql> -- 建立一個班級表
mysql> CREATE TABLE class(
    -> id int,
    ->   name varchar(50),
    ->   age tinyint(2),
    ->   sex enum('1','2')
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> 
mysql> -- 向班級中插入資料
mysql> INSERT INTO class (id,name,age,sex) VALUES (1,'班長',18,1);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO class (id,name,age,sex) VALUES (2,'小仙女',16,2);
Query OK, 1 row affected (0.00 sec)

mysql> -- 當所有的欄位都涉及到了,那麼括號中的欄位可以省略;當插入的欄位沒有全部涉及到,那麼則必須指定欄位。
mysql> INSERT INTO class VALUES (3, '小帥哥', 17, 1);
Query OK, 1 row affected (0.00 sec)

2、查詢資料

表中儲存了很多資料,其目的就是為了使用的時候可以立即查詢出來,所以資料庫的查詢語句的使用率是其他語句的數倍。下面我們介紹查詢語法:

格式:

SELECT [查詢欄位] FROM [表名] [條件語句] [顯示規則] [規則條件]

案例:

-- * 預設代表所有的欄位
mysql> SELECT * FROM class;
+------+-----------+------+------+
| id   | name      | age  | sex  |
+------+-----------+------+------+
|    1 | 班長      |   18 | 1    |
|    2 | 小仙女    |   16 | 2    |
|    3 | 小帥哥    |   17 | 1    |
+------+-----------+------+------+
3 rows in set (0.00 sec)

-- 查詢指定欄位
mysql> SELECT name FROM class;
+-----------+
| name      |
+-----------+
| 班長      |
| 小仙女    |
| 小帥哥    |
+-----------+
3 rows in set (0.00 sec)

1、條件語句(where)

條件語句是用來篩選資料的,主要用於查詢某些資料。下面我們介紹條件語句

  • 判斷條件
>                   :大於
<               :   小於
=               :等於
!= 和 <>  : 不等於
>=              : 大於等於
<=              : 小於等於
like            : 模糊查詢

and             : 並且
or              :或者

案例1:要求查詢出小仙女和小帥哥的資訊。

mysql> SELECT * FROM class where id > 1;
+------+-----------+------+------+
| id   | name      | age  | sex  |
+------+-----------+------+------+
|    2 | 小仙女    |   16 | 2    |
|    3 | 小帥哥    |   17 | 1    |
+------+-----------+------+------+
2 rows in set (0.01 sec)

案例2:要求查詢出班長的資訊

mysql> SELECT * FROM class where id = 1;
+------+--------+------+------+
| id   | name   | age  | sex  |
+------+--------+------+------+
|    1 | 班長   |   18 | 1    |
+------+--------+------+------+
1 row in set (0.00 sec)

案例3:要求查詢出女生有哪些

mysql> SELECT * FROM class WHERE sex = 2;
+------+-----------+------+------+
| id   | name      | age  | sex  |
+------+-----------+------+------+
|    2 | 小仙女    |   16 | 2    |
+------+-----------+------+------+
1 row in set (0.00 sec)

案例4:要求查詢出名字中包含小的資料

-- 模糊查詢中的%類似於正則表示式中的*,代表匹配所有的內容。
-- 前置% 代表的是以什麼結尾 和 後置% 代表以什麼開頭,如果兩者皆有,則表示包含。 
mysql> SELECT * FROM class WHERE name like '%小%';
+------+-----------+------+------+
| id   | name      | age  | sex  |
+------+-----------+------+------+
|    2 | 小仙女    |   16 | 2    |
|    3 | 小帥哥    |   17 | 1    |
+------+-----------+------+------+
2 rows in set (0.00 sec)

案例5:要求查詢出id既大於1,又小於3

mysql> SELECT * FROM class WHERE id > 1 AND id < 3;
+------+-----------+------+------+
| id   | name      | age  | sex  |
+------+-----------+------+------+
|    2 | 小仙女    |   16 | 2    |
+------+-----------+------+------+
1 row in set (0.00 sec)

案例6:要求查詢出下於等於1或者大於等於3

mysql> SELECT * FROM class WHERE id <= 1 OR id >= 3;
+------+-----------+------+------+
| id   | name      | age  | sex  |
+------+-----------+------+------+
|    1 | 班長      |   18 | 1    |
|    3 | 小帥哥    |   17 | 1    |
+------+-----------+------+------+
2 rows in set (0.00 sec)

2、排序(order by)

排序,顧名思義就是按照某種規則查詢出資料,預設情況下是按照從前到後查詢資料,但是也可以通過排序語法查詢出相關的資料。

格式:

SELECT [查詢欄位] FROM [表名] [顯示規則]

-- 排序的規則

ASC     :預設,正向排序
DESC    :反向排序

案例1:按照年齡的從大到小的順序查詢所有的資料

mysql> SELECT * FROM class ORDER BY age DESC;
+------+-----------+------+------+
| id   | name      | age  | sex  |
+------+-----------+------+------+
|    1 | 班長      |   18 | 1    |
|    3 | 小帥哥    |   17 | 1    |
|    2 | 小仙女    |   16 | 2    |
+------+-----------+------+------+
3 rows in set (0.00 sec)

3、去重(DISTINCT)

去重,顧名思義就是在查詢的資料中過濾掉重複資料,預設會顯示所有的資料,可以使用出重語法實現去掉重複資料。

格式:

去重是在指定需要被出重的語句之前新增去重關鍵字

案例:要求按照性別去出重

mysql> SELECT DISTINCT sex FROM class;
+------+
| sex  |
+------+
| 1    |
| 2    |
+------+
2 rows in set (0.00 sec)

4、別名

別名,顧名思義就是將欄位設定一個新的名字。

案例:要求計算出當前表中所有的行數

-- 計算行數的函式是count()
mysql> SELECT count(id) FROM class;
+-----------+
| count(id) |
+-----------+
|         3 |
+-----------+
1 row in set (0.00 sec)

-- 設定別名
mysql> SELECT count(id) '行數' FROM class;
+--------+
| 行數   |
+--------+
|      3 |
+--------+
1 row in set (0.00 sec)

5、常用的函式

函式,就是具備某種功能的工具。那麼在資料庫中使用函式就是通過函式實現某種具體的功能。

  • 計算行數的函式

案例:計算出當前資料有多少行

-- 計算行數的函式是count()
mysql> SELECT count(id) FROM class;
+-----------+
| count(id) |
+-----------+
|         3 |
+-----------+
1 row in set (0.00 sec)

  • 計算某一個欄位的和

案例:計算表中所有的年齡的總和

-- 計算和的函式是sum()
mysql> SELECT SUM(age) FROM class;
+----------+
| SUM(age) |
+----------+
|       51 |
+----------+
1 row in set (0.00 sec)

  • 計算平均值

案例:計算表中所有的年齡的平均值

-- 計算平均值的函式是avg()
mysql> SELECT AVG(age) FROM class;
+----------+
| AVG(age) |
+----------+
|  17.0000 |
+----------+
1 row in set (0.00 sec)

6、having語句

having也是一個條件判斷語句,類似於前面所講的where語句是用於做條件判斷的,但是有所不同的是where的條件作用於查詢之前的欄位,having是作用於查詢之後的語句。

案例1:所有的男生中,大於17歲的有哪些

mysql> SELECT * FROM class WHERE sex = 1 HAVING age > 17;
+------+--------+------+------+
| id   | name   | age  | sex  |
+------+--------+------+------+
|    1 | 班長   |   18 | 1    |
+------+--------+------+------+
1 row in set (0.00 sec)

案例2:查詢出一個月消費在2000元以上的同學

mysql> -- 建立一個消費表
mysql> CREATE TABLE consumption(
    -> id int,
    ->   name varchar(20),
    ->   money DECIMAL (8,2)
    -> );
ption VALUES (1,'小仙女',500.01);
INSERT INTO consumption VALUES (1,'小仙女',500.01);

-- 查詢出每個人的消費超過2000元的
SELECT SUM(money) moneys FROM consumption HAVING moneys > 2000;Query OK, 0 rows affected (0.03 sec)

mysql> 
mysql> -- 插入消費資料
mysql> INSERT INTO consumption VALUES (1,'小仙女',500.01);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO consumption VALUES (1,'小仙女',500.01);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO consumption VALUES (1,'小仙女',500.01);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO consumption VALUES (1,'小仙女',500.01);
Query OK, 1 row affected (0.00 sec)

mysql> 
mysql> -- 查詢出每個人的消費超過2000元的
mysql> SELECT SUM(money) moneys FROM consumption GROUP BY name HAVING moneys > 2000;
+---------+
| moneys  |
+---------+
| 2000.04 |
+---------+
1 row in set (0.00 sec)

7、分組(group by)

分組,顧名思義就是按照某種要求進行分組查詢,例如:查詢出所有人的消費總額。

案例:要求查詢出每一個人消費總額

mysql> SELECT SUM(money) FROM consumption GROUP BY name;
+------------+
| SUM(money) |
+------------+
|    3500.07 |
|    2000.04 |
+------------+
2 rows in set (0.00 sec)

3、修改表資料

在資料表中儲存的資料時常都會有所更改,例如:是否單身,是今天是否國慶。所以,怎麼會隨著一些事務的推移從而需要修改表資料,這個時候我們就需要用到MySQL UPDATE語句。

格式:

UPDATE <表名>  SET [修改的內容] [條件];

案例:修改單條資料(將資料表中的小仙女的年紀改成16歲)

mysql> -- 將資料表中的年紀改成17歲
mysql> UPDATE class SET age = 17;
Query OK, 0 rows affected (0.01 sec)
Rows matched: 5  Changed: 0  Warnings: 0
mysql> SELECT * FROM class;
+------+--------------+------+------+
| id   | name         | age  | sex  |
+------+--------------+------+------+
|    1 | 班長         |   17 | 1    |
|    2 | 小仙女       |   17 | 2    |
|    3 | 小帥哥       |   17 | 1    |
|    1 | 學習委員     |   17 | 1    |
|    2 | 組長         |   17 | 2    |
+------+--------------+------+------+
5 rows in set (0.00 sec)


mysql> -- 將資料表中的小仙女的年紀改成16歲
mysql> UPDATE class SET age = 16 WHERE name = "小仙女";
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM class;
+------+--------------+------+------+
| id   | name         | age  | sex  |
+------+--------------+------+------+
|    1 | 班長         |   17 | 1    |
|    2 | 小仙女       |   16 | 2    |
|    3 | 小帥哥       |   17 | 1    |
|    1 | 學習委員     |   17 | 1    |
|    2 | 組長         |   17 | 2    |
+------+--------------+------+------+
5 rows in set (0.01 sec)

案例2:修改多條資料(將學習委員的年紀修改成16,同時將其性別修改成女)

mysql> -- 將學習委員的年紀修改成16,同時將其性別修改成女
mysql> UPDATE class SET age = 16, sex=2 WHERE name = "學習委員";
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql> SELECT * FROM class;
+------+--------------+------+------+
| id   | name         | age  | sex  |
+------+--------------+------+------+
|    1 | 班長         |   17 | 1    |
|    2 | 小仙女       |   16 | 2    |
|    3 | 小帥哥       |   17 | 1    |
|    1 | 學習委員     |   16 | 2    |
|    2 | 組長         |   17 | 2    |
+------+--------------+------+------+
5 rows in set (0.00 sec)

4、刪除表資料

刪除表資料,就是當資料表中有錯誤或者沒有任何價值的資料時,通過SQL語句去將這部分資料刪除。

格式:

DELETE FROM <表名> [條件];

案例:刪除所有資料(千萬要謹慎使用)

mysql> DELETE FROM t1;
Query OK, 2 rows affected (0.00 sec)

mysql> SELECT * FROM t1;
Empty set (0.00 sec)

案例2:刪除某一部分資料(常用)

mysql> DELETE FROM test01 WHERE id = 2;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM test01;
+------+------+
| id   | age  |
+------+------+
|    3 |   18 |
+------+------+
1 row in set (0.00 sec)

案例3:清空資料表

mysql> -- 清空test01資料表中的所有的資料
mysql> DELETE FROM test01;
Query OK, 0 rows affected (0.00 sec)

mysql> TRUNCATE TABLE test01;
Query OK, 0 rows affected (0.00 sec)



-- DELETE 和 TRUNCATE 之間的區別?

    DELETE刪除的是資料,不刪除索引,TRUNCATE不僅刪除資料而且刪除索引。

5、資料表約束(索引約束和資料型別約束)

資料表的約束,從欄位名字上可以知道,它是為了控制資料而生的.。

1、主鍵索引約束

所謂的主鍵約束就是在資料表中(一般是id欄位),選擇一個欄位充當索引角色。強烈建議一個表中至少要有一個主鍵索引約束。下面我們介紹主鍵索引:

主鍵是一個欄位的型別,不能夠單獨的存在。

建立一個具有主鍵索引的資料表:

mysql> -- 建立一個具有主鍵索引的資料表
mysql> CREATE TABLE IF NOT EXISTS pm1(
    ->   id int PRIMARY KEY,
    ->   name VARCHAR(20)
    -> );
Query OK, 0 rows affected (0.01 sec)
mysql> SHOW CREATE TABLE pm1\G
*************************** 1. row ***************************
       Table: pm1
Create Table: CREATE TABLE `pm1` (
  `id` int(11) NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.01 sec)

mysql> DESC pm1;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

我們嘗試插入資料,看看有什麼區別?

mysql> -- 插入資料
mysql> INSERT INTO pm1 (id, name) VALUES (1, '小仙女'),(2,"小帥哥");
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM pm1;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 小仙女    |
|  2 | 小帥哥    |
+----+-----------+
2 rows in set (0.00 sec)

-- 我們可以看到插入資料和查詢資料沒有什麼區別,不急,將上述插入資料的SQL語句重新執行一遍
mysql> INSERT INTO pm1 (id, name) VALUES (1, '小仙女'),(2,"小帥哥");
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'

一旦欄位被標記成立主鍵,則其值是無法重複的。除此之外,主鍵算是MySQL中最快的索引之一。具體的底層演算法,我們將在後面的儲存引擎原理中詳細介紹。

1、自增長

在日常使用資料庫的時候常常不知道當天資料的主鍵索引的編號屬於哪一個,這個時候我們就很需要一個自動為我們填充主鍵編號的功能即為:自增長。

案例:自動填充主鍵

mysql> -- 建立一個具有主鍵索引的資料表
mysql> CREATE TABLE IF NOT EXISTS pm2(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> SHOW CREATE TABLE pm2\G
*************************** 1. row ***************************
       Table: pm2
Create Table: CREATE TABLE `pm2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> DESC pm2;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

建立完成資料表之後,填充資料時不增加id,看結果。

mysql> INSERT INTO pm2 (name) VALUES ( '小仙女'),("小帥哥");
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM pm2;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 小仙女    |
|  2 | 小帥哥    |
+----+-----------+
2 rows in set (0.00 sec)

除此之外,我們還可以設定自動增長的起始值。

mysql> -- 建立一個具有主鍵索引的資料表
mysql> CREATE TABLE IF NOT EXISTS pm3(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20)
    -> ) ENGINE=INNODB AUTO_INCREMENT=10000;
Query OK, 0 rows affected (0.03 sec)

mysql> DESC pm3;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> INSERT INTO pm3 (name) VALUES ( '小仙女'),("小帥哥");
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM pm3;
+-------+-----------+
| id    | name      |
+-------+-----------+
| 10000 | 小仙女    |
| 10001 | 小帥哥    |
+-------+-----------+
2 rows in set (0.00 sec)

2、新增主鍵

當資料表已經建立完畢了,我們需要為該表新增主鍵,如何新增呢?

格式:

ALTER TABLE <資料表> ADD PRIMARY KEY(欄位名稱);

案例:

mysql> -- 建立一個具有主鍵索引的資料表
mysql> CREATE TABLE IF NOT EXISTS pm4(
    ->   id int ,
    -> name VARCHAR(20)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> DESC pm4;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> ALTER TABLE pm4 ADD PRIMARY KEY(id);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC pm4;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

3、刪除主鍵

當資料表不需要主鍵時,我們可以嘗試將其刪除,下面我們來演示:

格式:

ALTER TABLE <資料表名> DROP PRIMARY KEY;

案例:

mysql> -- 建立一個具有主鍵索引的資料表
mysql> CREATE TABLE IF NOT EXISTS pm5(
    ->   id int PRIMARY KEY,
    -> name VARCHAR(20)
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)

mysql> DESC pm5;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> ALTER TABLE pm5 DROP PRIMARY KEY ;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC pm5;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

2、唯一索引約束

唯一索引約束跟主鍵索引類似,也是要求不允許重複,但是主鍵索引一般作用於id, 唯一索引可以作用於所有的欄位。同理唯一索引也是依賴於欄位,能夠單獨存在。

格式:

mysql> -- 建立一個具有主鍵索引的資料表
mysql> CREATE TABLE IF NOT EXISTS pm6(
    ->   id int PRIMARY KEY,
    -> name VARCHAR(20) UNIQUE KEY
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.02 sec)

mysql> DESC pm6;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  | UNI | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

建立之後,可以嘗試向其中name欄位插入相同的資料,看結果:

mysql> CREATE TABLE IF NOT EXISTS pm6(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) UNIQUE KEY
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO pm6 (name) VALUES ("小仙女");
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO pm6 (name) VALUES ("小仙女");
ERROR 1062 (23000): Duplicate entry '小仙女' for key 'name'

通過上文可以得出,欄位一旦加上了唯一索引,則不能夠重複。

3、檢查索引

檢查索引,顧名思義就是通過設定範圍,來管控資料。

案例:

mysql> CREATE TABLE IF NOT EXISTS pm7(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) ,
    -> code  tinyint(2) CHECK( code > 100 AND code < 200 )
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW CREATE TABLE pm7\G
*************************** 1. row ***************************
       Table: pm7
Create Table: CREATE TABLE `pm7` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `code` tinyint(2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> INSERT INTO pm7 (name, code) VALUES ("小仙女", 20);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM pm7;
+----+-----------+------+
| id | name      | code |
+----+-----------+------+
|  1 | 小仙女    |   20 |
+----+-----------+------+
1 row in set (0.00 sec)

4、外來鍵索引(不推薦使用)

外來鍵索引顧名思義就是依賴別的表的資料的一種索引,例如:我們寄快遞的時候,需要選擇地址:上海市青浦區華徐公路999號。

案例:

mysql> CREATE TABLE city(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    ->   name VARCHAR(20)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE city2(
    -> id int PRIMARY KEY AUTO_INCREMENT,
    ->   name VARCHAR(20),
    ->   fid int ,
    ->   FOREIGN KEY(fid) REFERENCES city(id)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> DESC city;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)

mysql> DESC city2;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
| fid   | int(11)     | YES  | MUL | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> INSERT INTO city2 (name,fid) VALUES ("青浦區", 1);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`linux13`.`city2`, CONSTRAINT `city2_ibfk_1` FOREIGN KEY (`fid`) REFERENCES `city` (`id`))

mysql> INSERT INTO city (name) VALUES ("上海市");
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO city2 (name,fid) VALUES ("青浦區", 1);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM city;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 上海市    |
+----+-----------+
1 row in set (0.00 sec)

mysql> SELECT * FROM city2;
+----+-----------+------+
| id | name      | fid  |
+----+-----------+------+
|  2 | 青浦區    |    1 |
+----+-----------+------+
1 row in set (0.00 sec)

city2變依賴於city變資料,當city表中沒有相關資料時,則不能夠新增資料到city2。

6、增加欄位

MySQL 資料表是由行和列構成的,通常把表的“列”稱為欄位(Field),把表的“行”稱為記錄(Record)。隨著業務的變化,可能需要在已有的表中新增新的欄位。

1、在開頭位置新增欄位

MySQL 預設在表的最後位置新增新欄位,如果希望在開頭位置(第一列的前面)新增新欄位,那麼可以使用 FIRST 關鍵字。

格式:

ALTER TABLE <表名> ADD <新欄位名> <資料型別> [約束條件] FIRST;
  • 案例
mysql> DESC pm7;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
| code  | tinyint(2)  | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> ALTER TABLE pm7 ADD address VARCHAR(20) FIRST;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC pm7;
+---------+-------------+------+-----+---------+----------------+
| Field   | Type        | Null | Key | Default | Extra          |
+---------+-------------+------+-----+---------+----------------+
| address | varchar(20) | YES  |     | NULL    |                |
| id      | int(11)     | NO   | PRI | NULL    | auto_increment |
| name    | varchar(20) | YES  |     | NULL    |                |
| code    | tinyint(2)  | YES  |     | NULL    |                |
+---------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

2、在中間位置新增欄位

MySQL 除了允許在表的開頭位置和末尾位置新增欄位外,還允許在中間位置(指定的欄位之後)新增欄位,此時需要使用 AFTER 關鍵字。

ALTER TABLE <表名> ADD <新欄位名> <資料型別> [約束條件] AFTER <已經存在的欄位名>;

AFTER 的作用是將新欄位新增到某個已有欄位後面。

mysql> DESC db01;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| name  | varchar(20) | YES  |     | NULL    |                |
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| addr  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> ALTER TABLE db01 ADD sex VARCHAR(20) AFTER id;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC db01;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| name  | varchar(20) | YES  |     | NULL    |                |
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| sex   | varchar(20) | YES  |     | NULL    |                |
| addr  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

3、在末尾位置新增欄位

一個完整的欄位包括欄位名、資料型別和約束條件。

ALTER TABLE <表名> ADD <新欄位名><資料型別>[約束條件];

對語法格式的說明如下:

  • <表名> 為資料表的名字
  • <新欄位名> 為所要新增的欄位的名字
  • <資料型別> 為所要新增的欄位能儲存資料的資料型別
  • [約束條件] 是可選的,用來對新增的欄位進行約束

使用 ALTER TABLE 語句新增一個 INT 型別的欄位 age,SQL 語句和執行結果如下:

mysql> DESC db01;
+-------+---------+------+-----+---------+----------------+
| Field | Type    | Null | Key | Default | Extra          |
+-------+---------+------+-----+---------+----------------+
| id    | int(11) | NO   | PRI | NULL    | auto_increment |
+-------+---------+------+-----+---------+----------------+
1 row in set (0.00 sec)

mysql> ALTER TABLE db01 ADD addr VARCHAR(20);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC db01;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| addr  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

4、欄位的瑣碎內容

將欄位中常用的約束一一列舉出來。

1、是否允許為空

是否為空顧名思義就是設定是否允許欄位為空。其格式是:NOT NULL

案例

mysql> CREATE TABLE IF NOT EXISTS pm8(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) NOT NULL
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE IF NOT EXISTS pm9(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) 
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO pm9 (id) VALUES (10);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO pm8 (id) VALUES (10);
ERROR 1364 (HY000): Field 'name' doesn't have a default value    '

mysql> INSERT INTO pm8 (name) VALUES ( '小仙女');
Query OK, 1 row affected (0.01 sec)

2、預設值

預設值,顧名思義就是給欄位設定一個預設值,當欄位沒有新增任何值的時候,使用預設值進行填充。

案例:

mysql> CREATE TABLE IF NOT EXISTS pm10(
    ->   id int PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) DEFAULT "小仙女"
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)

mysql> DESC pm10;
+-------+-------------+------+-----+-----------+----------------+
| Field | Type        | Null | Key | Default   | Extra          |
+-------+-------------+------+-----+-----------+----------------+
| id    | int(11)     | NO   | PRI | NULL      | auto_increment |
| name  | varchar(20) | YES  |     | 小仙女    |                |
+-------+-------------+------+-----+-----------+----------------+
2 rows in set (0.00 sec)

mysql> INSERT INTO pm10 (id) VALUES (10);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM pm10;
+----+-----------+
| id | name      |
+----+-----------+
| 10 | 小仙女    |
+----+-----------+
1 row in set (0.00 sec)

3、欄位註釋

欄位註釋,顧名思義就是給欄位一個註釋,有利於後期維護的時候快速理解欄位含義。

案例:

-- 欄位註釋
mysql> CREATE TABLE IF NOT EXISTS pm11(
    ->   id int PRIMARY KEY AUTO_INCREMENT COMMENT "主鍵欄位",
    -> name VARCHAR(20) DEFAULT "小仙女" COMMENT "名字"
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW CREATE TABLE pm11\G
*************************** 1. row ***************************
       Table: pm11
Create Table: CREATE TABLE `pm11` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵欄位',
  `name` varchar(20) DEFAULT '小仙女' COMMENT '名字',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)


-- 表註釋
mysql> CREATE TABLE IF NOT EXISTS pm12(
    ->   id int PRIMARY KEY AUTO_INCREMENT COMMENT "主鍵欄位",
    -> name VARCHAR(20) DEFAULT "小仙女" COMMENT "名字"
    -> ) ENGINE=INNODB COMMENT "仙女表";
Query OK, 0 rows affected (0.02 sec)

mysql> SHOW CREATE TABLE pm12\G
*************************** 1. row ***************************
       Table: pm12
Create Table: CREATE TABLE `pm12` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵欄位',
  `name` varchar(20) DEFAULT '小仙女' COMMENT '名字',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='仙女表'
1 row in set (0.00 sec)

7、連表查詢

兩個或多個表至之間通過某種關係,按照某種規則合併起來查詢出來的資料即為連表查詢,連表查詢是企業中常用一種查詢資料方式,在關係型資料庫中連表查詢是很常見的。但是連表查詢僅僅限於同一個資料庫內多張資料表相互連結,不同資料庫中的資料便無法使用連表查詢。

1、內連線(INNER JOIN )

把兩個資料表中的所有的資料一次性按照某種條件一次性查詢出來。

案例

mysql> use linux13;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> 
mysql> CREATE TABLE IF NOT EXISTS student(
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) NOT NULL COMMENT "學生名稱",
    -> age TINYINT(2) NOT NULL DEFAULT 18 COMMENT "年齡"
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE IF NOT EXISTS major (
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) NOT NULL COMMENT "專業名稱"
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> CREATE TABLE IF NOT EXISTS student_major(
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> stu_id INT NOT NULL COMMENT "學生表ID",
    -> m_id INT NOT NULL COMMENT "專業表ID"
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE IF NOT EXISTS teacher(
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> name VARCHAR(20) NOT NULL COMMENT "老師名稱"
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE IF NOT EXISTS tearch_major(
    -> id INT PRIMARY KEY AUTO_INCREMENT,
    -> tea_id INT NOT NULL COMMENT "老師表ID",
    -> m_id INT NOT NULL COMMENT "專業表ID"
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO student (name,age) VALUES ("小明", 18),("小紅", 17),("小花", 16);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> INSERT INTO major (name) VALUES ("數學"),("英語"),("毛概");
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> INSERT INTO teacher (name) VALUES ("李鐵錘"),("石林"),("為李飛");
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * FROM student;
+----+--------+-----+
| id | name   | age |
+----+--------+-----+
|  1 | 小明   |  18 |
|  2 | 小紅   |  17 |
|  3 | 小花   |  16 |
+----+--------+-----+
3 rows in set (0.00 sec)

mysql> select * FROM teacher;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 李鐵錘    |
|  2 | 石林      |
|  3 | 為李飛    |
+----+-----------+
3 rows in set (0.00 sec)
mysql> select * FROM major;
+----+--------+
| id | name   |
+----+--------+
|  1 | 數學   |
|  2 | 英語   |
|  3 | 毛概   |
+----+--------+
3 rows in set (0.00 sec)
INSERT INTO student_major (stu_id, m_id) VALUES (1, 1),(1,2);
INSERT INTO student_major (stu_id, m_id) VALUES (2, 1),(2,3);
INSERT INTO student_major (stu_id, m_id) VALUES (3, 1),(3,2),(3,3);
mysql> select * from student_major;
+----+--------+------+
| id | stu_id | m_id |
+----+--------+------+
|  1 |      1 |    1 |
|  2 |      1 |    2 |
|  3 |      2 |    1 |
|  4 |      2 |    3 |
|  5 |      3 |    1 |
|  6 |      3 |    2 |
|  7 |      3 |    3 |
+----+--------+------+
7 rows in set (0.00 sec)
mysql> INSERT INTO tearch_major (tea_id, m_id) VALUES (1,3),(2,1),(3,2);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0
mysql> select * FROM tearch_major;
+----+--------+------+
| id | tea_id | m_id |
+----+--------+------+
|  1 |      1 |    3 |
|  2 |      2 |    1 |
|  3 |      3 |    2 |
+----+--------+------+
3 rows in set (0.00 sec)

資料建立完畢之後,我們有如下幾個需求:

1、查詢出小明選修哪幾門課?

-- 按照既學的內容,我們可以得出如下:

mysql> SELECT * FROM student WHERE id = 1;
+----+--------+-----+
| id | name   | age |
+----+--------+-----+
|  1 | 小明   |  18 |
+----+--------+-----+
1 row in set (0.00 sec)

mysql> SELECT * FROM student_major WHERE stu_id = 1;
+----+--------+------+
| id | stu_id | m_id |
+----+--------+------+
|  1 |      1 |    1 |
|  2 |      1 |    2 |
+----+--------+------+
2 rows in set (0.01 sec)

mysql> SELECT * FROM major WHERE id = 1 or id = 2;
+----+--------+
| id | name   |
+----+--------+
|  1 | 數學   |
|  2 | 英語   |
+----+--------+
2 rows in set (0.00 sec)

-- 通過上面可知,如果需要查詢出選修的課程需要三步,非常的繁瑣,那麼我們介紹一下連表查詢。
mysql> SELECT * FROM student INNER JOIN  student_major ON student.id = student_major.stu_id WHERE student.id = 1;
+----+--------+-----+----+--------+------+
| id | name   | age | id | stu_id | m_id |
+----+--------+-----+----+--------+------+
|  1 | 小明   |  18 |  1 |      1 |    1 |
|  1 | 小明   |  18 |  2 |      1 |    2 |
+----+--------+-----+----+--------+------+
2 rows in set (0.00 sec)
-- 由上可知,資料庫連表查詢非常方便快捷。

mysql> SELECT * FROM student INNER JOIN  student_major ON student.id = student_major.stu_id  INNER JOIN major ON student_major.m_id = major.id WHERE student.id = 1;
+----+--------+-----+----+--------+------+----+--------+
| id | name   | age | id | stu_id | m_id | id | name   |
+----+--------+-----+----+--------+------+----+--------+
|  1 | 小明   |  18 |  1 |      1 |    1 |  1 | 數學   |
|  1 | 小明   |  18 |  2 |      1 |    2 |  2 | 英語   |
+----+--------+-----+----+--------+------+----+--------+
2 rows in set (0.00 sec)

-- 由上簡化得來
mysql> SELECT student.id,student.name,student.age, major.name FROM student INNER JOIN  student_major ON student.id = student_major.stu_id  INNER JOIN major ON student_major.m_id = major.id WHERE student.id = 1;
+----+--------+-----+--------+
| id | name   | age | name   |
+----+--------+-----+--------+
|  1 | 小明   |  18 | 數學   |
|  1 | 小明   |  18 | 英語   |
+----+--------+-----+--------+
2 rows in set (0.00 sec)

2、查詢出小花選修的課的老師有哪些?

mysql> SELECT  student.id,student.name,student.age, major.name,teacher.name  FROM  student  INNER JOIN  student_major ON student.id = student_major.stu_id   INNER JOIN major ON student_major.m_id = major.id  INNER JOIN tearch_major ON tearch_major.m_id = major.id INNER JOIN teacher ON teacher.id =  tearch_major.tea_id WHERE student.id = 3;
+----+--------+-----+--------+-----------+
| id | name   | age | name   | name      |
+----+--------+-----+--------+-----------+
|  3 | 小花   |  16 | 毛概   | 李鐵錘    |
|  3 | 小花   |  16 | 數學   | 石林      |
|  3 | 小花   |  16 | 英語   | 為李飛    |
+----+--------+-----+--------+-----------+
3 rows in set (0.00 sec)

2、左連線(LEFT JOIN)

左連線顧名思義就是以左邊的表為主表,其他的表為副表;也就是說會把左邊表中所有的符合條件的資料全部查詢出來,至於後面的表有沒有內容不管,沒有內容則用空來代替。

案例:

-- 插入一個學生
INSERT INTO student (name, age) VALUES ("鐵錘", 18);

SELECT * FROM student LEFT JOIN student_major ON student.id = student_major.stu_id ;
SELECT * FROM student INNER JOIN student_major ON student.id = student_major.stu_id;

mysql> SELECT * FROM student LEFT JOIN student_major ON student.id = student_major.stu_id ;
+----+--------+-----+------+--------+------+
| id | name   | age | id   | stu_id | m_id |
+----+--------+-----+------+--------+------+
|  1 | 小明   |  18 |    1 |      1 |    1 |
|  1 | 小明   |  18 |    2 |      1 |    2 |
|  2 | 小紅   |  17 |    3 |      2 |    1 |
|  2 | 小紅   |  17 |    4 |      2 |    3 |
|  3 | 小花   |  16 |    5 |      3 |    1 |
|  3 | 小花   |  16 |    6 |      3 |    2 |
|  3 | 小花   |  16 |    7 |      3 |    3 |
|  4 | 鐵錘   |  18 | NULL |   NULL | NULL |
+----+--------+-----+------+--------+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM student INNER JOIN student_major ON student.id = student_major.stu_id;
+----+--------+-----+----+--------+------+
| id | name   | age | id | stu_id | m_id |
+----+--------+-----+----+--------+------+
|  1 | 小明   |  18 |  1 |      1 |    1 |
|  1 | 小明   |  18 |  2 |      1 |    2 |
|  2 | 小紅   |  17 |  3 |      2 |    1 |
|  2 | 小紅   |  17 |  4 |      2 |    3 |
|  3 | 小花   |  16 |  5 |      3 |    1 |
|  3 | 小花   |  16 |  6 |      3 |    2 |
|  3 | 小花   |  16 |  7 |      3 |    3 |
+----+--------+-----+----+--------+------+
7 rows in set (0.00 sec)

3、右連結(Right JOIN)

右連結顧名思義就是用右邊表作為主表,其他表作為副表。也就是說,右連結是會把右邊的表中的所有的資料全部都查詢出來,至於左邊的表如果沒有資料既用空代替。

案例:

INSERT INTO student_major (stu_id,m_id) VALUES (4, 5);

mysql> SELECT * FROM  major LEFT JOIN student_major ON major.id = student_major.m_id;
+----+--------+------+--------+------+
| id | name   | id   | stu_id | m_id |
+----+--------+------+--------+------+
|  1 | 數學   |    1 |      1 |    1 |
|  2 | 英語   |    2 |      1 |    2 |
|  1 | 數學   |    3 |      2 |    1 |
|  3 | 毛概   |    4 |      2 |    3 |
|  1 | 數學   |    5 |      3 |    1 |
|  2 | 英語   |    6 |      3 |    2 |
|  3 | 毛概   |    7 |      3 |    3 |
|  4 | Linux  | NULL |   NULL | NULL |
+----+--------+------+--------+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM  major RIGHT JOIN student_major ON major.id = student_major.m_id;
+------+--------+----+--------+------+
| id   | name   | id | stu_id | m_id |
+------+--------+----+--------+------+
|    1 | 數學   |  1 |      1 |    1 |
|    1 | 數學   |  3 |      2 |    1 |
|    1 | 數學   |  5 |      3 |    1 |
|    2 | 英語   |  2 |      1 |    2 |
|    2 | 英語   |  6 |      3 |    2 |
|    3 | 毛概   |  4 |      2 |    3 |
|    3 | 毛概   |  7 |      3 |    3 |
| NULL | NULL   |  8 |      4 |    5 |
+------+--------+----+--------+------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM  major INNER JOIN student_major ON major.id = student_major.m_id;
+----+--------+----+--------+------+
| id | name   | id | stu_id | m_id |
+----+--------+----+--------+------+
|  1 | 數學   |  1 |      1 |    1 |
|  2 | 英語   |  2 |      1 |    2 |
|  1 | 數學   |  3 |      2 |    1 |
|  3 | 毛概   |  4 |      2 |    3 |
|  1 | 數學   |  5 |      3 |    1 |
|  2 | 英語   |  6 |      3 |    2 |
|  3 | 毛概   |  7 |      3 |    3 |
+----+--------+----+--------+------+
7 rows in set (0.00 sec)

4、合併資料

顧名思義就是將多個SQL語句查詢出來的資料合併一次性查詢出來。需要注意的是,兩邊的欄位必須一致。

案例:

mysql> SELECT name,age FROM student UNION SELECT * FROM teacher;
+--------+-----------+
| name   | age       |
+--------+-----------+
| 小明   | 18        |
| 小紅   | 17        |
| 小花   | 16        |
| 鐵錘   | 18        |
| 1      | 李鐵錘    |
| 2      | 石林      |
| 3      | 為李飛    |
+--------+-----------+
7 rows in set (0.00 sec)

8、子查詢

子查詢顧名思義就是在SQL中依賴於另一個SQL語句的結果來共同查詢一個結果。每一個子查詢語句只能夠返回一條資料。在工作用極其不建議使用子查詢,因為子查詢的效能非常低。

案例:

mysql> SELECT * FROM student WHERE id = (SELECT DISTINCT stu_id FROM student_major LIMIT 1);
+----+--------+-----+
| id | name   | age |
+----+--------+-----+
|  1 | 小明   |  18 |
+----+--------+-----+
1 row in set (0.00 sec)