MySQL - MySQL 8.0(三)進階操作:生成列(generated column)

此學習文是基於MySQL 8.0寫的
得益於大神朋友的悉心指導解決不少坑,才寫出此文,向大神奉上膝蓋

  生成列(generated column)的值是根據列定義中包含的表達式計算得出的。 生成列包含下面兩種類型:

  • virtual(虛擬):當從表中讀取記錄時,將動態計算該列。
  • stored(存儲):當向表中寫入新記錄時,將計算該列並將其存儲爲常規列。

  virtual生成列比stored生成列更有用,因爲一個虛擬的列不佔用任何存儲空間。你可以使用觸發器模擬stored生成列的行爲。

舉個栗子

1. 創建表時

  假設你的應用程序從t_employees_generated表中檢索數據時,使用full_name表示concat(first_name, ' ', last_name),而不是使用表達式來表示,從而實現虛擬列實時計算full_name

# 創建測試表
mysql> create table if not exists employees.t_employees_generated (
    -> emp_no int(11) not null,
    -> birth_date date not null,
    -> first_name varchar(14) not null,
    -> last_name varchar(16) not null,
    -> gender enum('M', 'F') not null,
    -> hire_date date not null,
    -> full_name varchar(30) as (concat(first_name, ' ', last_name)),
    -> primary key (emp_no),
    -> key name (first_name, last_name)
    -> ) engine=innodb default charset=utf8mb4;
Query OK, 0 rows affected, 1 warning (0.04 sec)

  請注意,應該根據虛擬列修改插入語句。你可以這樣使用full insert

# 執行插入
mysql> insert into employees.t_employees_generated 
    -> (emp_no, birth_date, first_name, last_name, gender, hire_date) 
    -> values 
    -> (123456, '1987-10-02', 'ABC', 'XYZ', 'F', '2008-07-28');
Query OK, 1 row affected (0.11 sec)

# 驗證數據
mysql> select * from employees.t_employees_generated where emp_no = '123456';
+--------+------------+------------+-----------+--------+------------+-----------+
| emp_no | birth_date | first_name | last_name | gender | hire_date  | full_name |
+--------+------------+------------+-----------+--------+------------+-----------+
| 123456 | 1987-10-02 | ABC        | XYZ       | F      | 2008-07-28 | ABC XYZ   |
+--------+------------+------------+-----------+--------+------------+-----------+
1 row in set (0.00 sec)

  如果要在INSERT語句中包含full_name,就只能將其指定爲DEFAULT

# 執行插入
mysql> insert into employees.t_employees_generated 
    -> (emp_no, birth_date, first_name, last_name, gender, hire_date, full_name) 
    -> values 
    -> (123457, '1987-10-02', 'ABC', 'XYZ', 'F', '2008-07-28', DEFAULT);
Query OK, 1 row affected (0.01 sec)

# 驗證數據
mysql> select * from employees.t_employees_generated where emp_no = '123457';
+--------+------------+------------+-----------+--------+------------+-----------+
| emp_no | birth_date | first_name | last_name | gender | hire_date  | full_name |
+--------+------------+------------+-----------+--------+------------+-----------+
| 123457 | 1987-10-02 | ABC        | XYZ       | F      | 2008-07-28 | ABC XYZ   |
+--------+------------+------------+-----------+--------+------------+-----------+
1 row in set (0.00 sec)

  其他值都會引發ERROR 3105 (HY000):錯誤,不允許在t_employees_generated表中爲生成的列full_name指定值:

mysql> insert into employees.t_employees_generated 
    -> (emp_no, birth_date, first_name, last_name, gender, hire_date, full_name) 
    -> values 
    -> (123458, '1987-10-02', 'ABC', 'XYZ', 'F', '2008-07-28', 'TEST');
ERROR 3105 (HY000): The value specified for generated column 'full_name' in table 't_employees_generated' is not allowed.

2. 已有表時

  如果你已經創建了表並希望添加新的生成列,請執行ALTER TABLE語句

# 修改表結構 - 新增生成列
mysql> alter table employees.t_employees_generated add hire_date_year year as (year(hire_date)) virtual;
Query OK, 0 rows affected (0.12 sec)
Records: 0  Duplicates: 0  Warnings: 0

# 驗證數據
mysql> select * from employees.t_employees_generated where emp_no = '123456';
+--------+------------+------------+-----------+--------+------------+-----------+----------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date  | full_name | hire_date_year |
+--------+------------+------------+-----------+--------+------------+-----------+----------------+
| 123456 | 1987-10-02 | ABC        | XYZ       | F      | 2008-07-28 | ABC XYZ   |           2008 |
+--------+------------+------------+-----------+--------+------------+-----------+----------------+
1 row in set (0.00 sec)

# 查看錶結構
mysql> desc employees.t_employees_generated;
+----------------+---------------+------+-----+---------+-------------------+
| Field          | Type          | Null | Key | Default | Extra             |
+----------------+---------------+------+-----+---------+-------------------+
| emp_no         | int(11)       | NO   | PRI | NULL    |                   |
| birth_date     | date          | NO   |     | NULL    |                   |
| first_name     | varchar(14)   | NO   | MUL | NULL    |                   |
| last_name      | varchar(16)   | NO   |     | NULL    |                   |
| gender         | enum('M','F') | NO   |     | NULL    |                   |
| hire_date      | date          | NO   |     | NULL    |                   |
| full_name      | varchar(30)   | YES  |     | NULL    | VIRTUAL GENERATED |
| hire_date_year | year(4)       | YES  |     | NULL    | VIRTUAL GENERATED |
+----------------+---------------+------+-----+---------+-------------------+
8 rows in set (0.00 sec)

詳情參閱 https://dev.mysql.com/doc/refman/8.0/en/create-table-generated-columns.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章