第4章:表管理
4.0 引言
MySQL :: 員工樣例數據庫 :: 3 安裝
https://dev.mysql.com/doc/employee/en/employees-installation.html
Employees 數據庫與幾種不同的 存儲引擎,默認情況下啟用 InnoDB 引擎。編輯 文件并調整 comments 選擇不同的存儲引擎:employees.sql
SET default_storage_engine = InnoDB;
– set storage_engine = MyISAM;
– set storage_engine = Falcon;
– set storage_engine = PBXT;
– set storage_engine = Maria;
? MySQL 5.7 或更早:使用 storage_engine。
? MySQL 8.0+:使用 default_storage_engine。
D:\sql\Mysql_learning\employee\mysql\master>mysql -u root -p -t < employees.sql
Enter password: ****
+-----------------------------+
| INFO |
+-----------------------------+
| CREATING DATABASE STRUCTURE |
+-----------------------------+
+------------------------+
| INFO |
+------------------------+
| storage engine: InnoDB |
+------------------------+
+---------------------+
| INFO |
+---------------------+
| LOADING departments |
+---------------------+
+-------------------+
| INFO |
+-------------------+
| LOADING employees |
+-------------------+
+------------------+
| INFO |
+------------------+
| LOADING dept_emp |
+------------------+
+----------------------+
| INFO |
+----------------------+
| LOADING dept_manager |
+----------------------+
+----------------+
| INFO |
+----------------+
| LOADING titles |
+----------------+
+------------------+
| INFO |
+------------------+
| LOADING salaries |
+------------------+
+---------------------+
| data_load_time_diff |
+---------------------+
| 00:01:09 |
+---------------------+
mysql> SOURCE D:/sql/Mysql_learning/employee/mysql/master/test_employees_md5.sql;
Database changed
+----------------------+
| INFO |
+----------------------+
| TESTING INSTALLATION |
+----------------------+
1 row in set (0.00 sec)Query OK, 0 rows affected, 2 warnings (0.00 sec)Query OK, 0 rows affected (0.06 sec)Query OK, 0 rows affected (0.04 sec)Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0+--------------+------------------+----------------------------------+
| table_name | expected_records | expected_crc |
+--------------+------------------+----------------------------------+
| departments | 9 | d1af5e170d2d1591d776d5638d71fc5f |
| dept_emp | 331603 | ccf6fe516f990bdaa49713fc478701b7 |
| dept_manager | 24 | 8720e2f0853ac9096b689c14664f847e |
| employees | 300024 | 4ec56ab5ba37218d187cf6ab09ce1aa1 |
| salaries | 2844047 | fd220654e95aea1b169624ffe3fca934 |
| titles | 443308 | bfa016c472df68e70a03facafa1bc0a8 |
+--------------+------------------+----------------------------------+
6 rows in set (0.00 sec)Query OK, 0 rows affected, 1 warning (0.01 sec)Query OK, 0 rows affected (0.04 sec)Query OK, 0 rows affected (0.00 sec)Query OK, 300024 rows affected, 1 warning (6.19 sec)
Records: 300024 Duplicates: 0 Warnings: 1Query OK, 1 row affected (0.29 sec)Query OK, 0 rows affected (0.00 sec)Query OK, 9 rows affected, 1 warning (0.01 sec)
Records: 9 Duplicates: 0 Warnings: 1Query OK, 1 row affected (0.01 sec)Query OK, 0 rows affected (0.00 sec)Query OK, 24 rows affected, 1 warning (0.01 sec)
Records: 24 Duplicates: 0 Warnings: 1Query OK, 1 row affected (0.01 sec)Query OK, 0 rows affected (0.00 sec)Query OK, 331603 rows affected, 1 warning (6.28 sec)
Records: 331603 Duplicates: 0 Warnings: 1Query OK, 1 row affected (0.38 sec)Query OK, 0 rows affected (0.00 sec)Query OK, 443308 rows affected, 1 warning (9.02 sec)
Records: 443308 Duplicates: 0 Warnings: 1Query OK, 1 row affected (0.43 sec)Query OK, 0 rows affected (0.00 sec)Query OK, 2844047 rows affected, 1 warning (51.55 sec)
Records: 2844047 Duplicates: 0 Warnings: 1Query OK, 1 row affected (2.60 sec)Query OK, 0 rows affected (0.07 sec)+--------------+------------------+----------------------------------+
| table_name | found_records | found_crc |
+--------------+------------------+----------------------------------+
| departments | 9 | d1af5e170d2d1591d776d5638d71fc5f |
| dept_emp | 331603 | ccf6fe516f990bdaa49713fc478701b7 |
| dept_manager | 24 | 8720e2f0853ac9096b689c14664f847e |
| employees | 300024 | 4ec56ab5ba37218d187cf6ab09ce1aa1 |
| salaries | 2844047 | fd220654e95aea1b169624ffe3fca934 |
| titles | 443308 | bfa016c472df68e70a03facafa1bc0a8 |
+--------------+------------------+----------------------------------+
6 rows in set (0.00 sec)+--------------+---------------+-----------+
| table_name | records_match | crc_match |
+--------------+---------------+-----------+
| departments | OK | ok |
| dept_emp | OK | ok |
| dept_manager | OK | ok |
| employees | OK | ok |
| salaries | OK | ok |
| titles | OK | ok |
+--------------+---------------+-----------+
6 rows in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)Query OK, 0 rows affected (0.00 sec)+------------------+
| computation_time |
+------------------+
| 00:01:18 |
+------------------+
1 row in set (0.01 sec)Query OK, 0 rows affected (0.04 sec)+---------+--------+
| summary | result |
+---------+--------+
| CRC | OK |
| count | OK |
+---------+--------+
2 rows in set (0.00 sec)
mysql>
SQL CREATE TABLE LIKE 用法及示例
在 MySQL 中,CREATE TABLE LIKE 是一種用于創建新表的語法,該新表的結構與現有表完全相同,但不包含源表中的數據1。以下是詳細的用法和示例:
import mysql.connector
from pathlib import Path
import redef merge_sql_files(main_sql_path):"""遞歸合并所有被引用的SQL文件"""main_path = Path(main_sql_path)base_dir = main_path.parentmerged_sql = []with open(main_path, 'r', encoding='utf-8') as f:for line in f:# 處理source命令if line.strip().startswith('source'):# 提取被引用的文件名match = re.search(r'source\s+[\'"](.+?)[\'"]|source\s+(\S+)', line.strip())ref_file = match.group(1) or match.group(2)ref_path = base_dir / ref_fileif ref_path.exists():merged_sql.append(f"\n-- 開始導入: {ref_file}\n")merged_sql.append(merge_sql_files(str(ref_path)))merged_sql.append(f"\n-- 完成導入: {ref_file}\n")else:raise FileNotFoundError(f"無法找到引用的SQL文件: {ref_path}")else:# 移除DELIMITER等客戶端命令if not line.strip().upper().startswith(('DELIMITER', 'USE ', 'CONNECT ')):merged_sql.append(line)return ''.join(merged_sql)def execute_mega_sql(db_config, full_sql):"""執行大型SQL腳本"""cnx = mysql.connector.connect(**db_config)cursor = cnx.cursor()try:# 設置更大的緩沖區cursor.execute("SET GLOBAL max_allowed_packet=256*1024*1024")cursor.execute("SET GLOBAL net_buffer_length=1000000")# 分割并執行SQL語句statements = [s.strip() for s in full_sql.split(';') if s.strip()]for stmt in statements:try:# 確保語句以分號結尾sql = stmt if stmt.endswith(';') else stmt + ';'for result in cursor.execute(sql, multi=True):if result.with_rows:result.fetchall() # 消費結果集print(f"執行成功: {result.statement[:100]}...")cnx.commit()except mysql.connector.Error as err:print(f"跳過錯誤: {err}\n語句: {stmt[:200]}...")cnx.rollback()except Exception as e:print(f"意外錯誤: {e}")cnx.rollback()finally:cursor.close()cnx.close()# 配置信息
db_config = {'host': 'localhost','user': 'root','password': 'root','database': 'cookbook'
}# 主SQL文件路徑
main_sql_path = r"D:\sql\Mysql_learning\employee\mysql\dataset_small\employee.sql"try:print("開始合并SQL文件...")full_sql = merge_sql_files(main_sql_path)# 可選:保存合并后的文件供檢查with open('merged_script.sql', 'w', encoding='utf-8') as f:f.write(full_sql)print("開始執行SQL腳本...")execute_mega_sql(db_config, full_sql)print("數據導入成功完成!")except Exception as e:
print(f"導入失敗: {str(e)}")
def verify_import():tables = ['employee', 'department', 'dept_emp','dept_manager', 'title', 'salary']cnx = mysql.connector.connect(**db_config)cursor = cnx.cursor(dictionary=True)for table in tables:cursor.execute(f"SELECT COUNT(*) as count FROM {table}")result = cursor.fetchone()print(f"{table}表記錄數: {result['count']}")cursor.close()cnx.close()verify_import()
employee表記錄數: 1000
department表記錄數: 9
dept_emp表記錄數: 1103
dept_manager表記錄數: 16
title表記錄數: 1470
salary表記錄數: 9488
mysql> SHOW TABLES;
+-----------------------+
| Tables_in_cookbook |
+-----------------------+
| actors |
| adcount |
| al_winner |
| app_log |
| artist |
| book_authors |
| book_vendor |
| booksales |
| catalog_list |
| cd |
| city |
| color |
| cow_color |
| cow_order |
| current_dept_emp |
| customers |
| date_val |
| datetbl |
| datetime_val |
| department |
| dept_emp |
| dept_emp_latest_date |
| dept_manager |
| dialogue |
| dialogue_analysis |
| die |
| doremi |
| drawing |
| driver_log |
| employee |
| expt |
| formula1 |
| goods_characteristics |
| goods_shops |
| groceries |
| groceries_order_items |
| hitcount |
| hitlog |
| hostip |
| hostname |
| housewares |
| housewares2 |
| housewares3 |
| housewares4 |
| httpdlog |
| httpdlog2 |
| hw_category |
| image |
| ingredient |
| insect |
| inv_item |
| invoice |
| item |
| limbs |
| limbs_backup |
| limbs_stats |
| mail |
| mail2 |
| mail_view |
| marathon |
| mark_log |
| metal |
| money |
| movies |
| movies_actors |
| movies_actors_link |
| mytable |
| name |
| news |
| newsstaff |
| numbers |
| obs |
| occasion |
| painting |
| passtbl |
| passwd |
| patients |
| perl_session |
| person |
| php_session |
| phrase |
| player_stats |
| player_stats2 |
| poi |
| poll_vote |
| profile |
| profile_contact |
| rainfall |
| rand_names |
| rank |
| ranks |
| reviews |
| roster |
| ruby_session |
| salary |
| sales_region |
| sales_tax_rate |
| sales_volume |
| sibling |
| some table |
| standings1 |
| standings2 |
| states |
| str_val |
| sundays |
| taxpayer |
| testscore |
| testscore_withmisses |
| testscore_withmisses2 |
| time_val |
| title |
| tmp |
| tomcat_role |
| tomcat_session |
| tomcat_user |
| top_names |
| trip_leg |
| trip_log |
| tsdemo |
| weatherdata |
| weekday |
+-----------------------+
121 rows in set (0.01 sec)
mysql> SELECT * FROM department LIMIT 5;
+---------+------------------+
| dept_no | dept_name |
+---------+------------------+
| d009 | Customer Service |
| d005 | Development |
| d002 | Finance |
| d003 | Human Resources |
| d001 | Marketing |
+---------+------------------+
5 rows in set (0.00 sec)mysql> SELECT COUNT(*) FROM employee;
+----------+
| COUNT(*) |
+----------+
| 1000 |
+----------+
1 row in set (0.01 sec)
基本語法
CREATE TABLE new_table_name LIKE existing_table_name;
new_table_name:要創建的新表的名稱。
existing_table_name:作為模板的現有表的名稱。
此語法會復制 existing_table_name 表的所有列定義、索引以及約束到 new_table_name 表中1。
示例代碼
以下是一個具體的例子,展示如何使用 CREATE TABLE LIKE 創建一個新表:
– 假設有一個名為 employees
的表
CREATE TABLE employees_backup LIKE employees;
上述語句將創建一個名為 employees_backup 的新表,其結構與 employees 表完全一致,但不包含任何數據1。
如果需要同時復制數據,則可以結合 INSERT INTO SELECT 使用:
– 復制數據到新表
INSERT INTO employees_backup SELECT * FROM employees;
注意事項
CREATE TABLE LIKE 不會復制觸發器或視圖等其他數據庫對象3。
在不同數據庫系統中,LIKE 的支持情況可能有所不同。例如,PostgreSQL 支持類似的 CREATE TABLE AS 功能,但行為略有差異2。
結合 INSERT INTO SELECT 的完整示例
以下是一個完整的示例,展示如何結合 CREATE TABLE LIKE 和 INSERT INTO SELECT 創建并填充新表:
– 創建結構相同的空表
CREATE TABLE employees_backup LIKE employees;
– 將數據從原表插入到新表
INSERT INTO employees_backup SELECT * FROM employees WHERE department = ‘Sales’;
上述代碼將創建一個名為 employees_backup 的新表,并僅復制屬于 Sales 部門的數據
4.1 克隆表
mysql> insert into mail2 select * from mail where srcuser = 'barb';
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0mysql> select * from mail2;
+---------------------+---------+---------+---------+---------+-------+
| t | srcuser | srchost | dstuser | dsthost | size |
+---------------------+---------+---------+---------+---------+-------+
| 2006-05-11 10:15:08 | barb | saturn | tricia | mars | 58274 |
| 2006-05-13 13:59:18 | barb | saturn | tricia | venus | 271 |
| 2006-05-14 14:42:21 | barb | venus | barb | venus | 98151 |
+---------------------+---------+---------+---------+---------+-------+
3 rows in set (0.00 sec)
4.2 將查詢結果保存到表中
一、CREATE TABLE … LIKE + INSERT INTO … SELECT
原理
結構復制:通過 LIKE 關鍵字復制源表的完整結構(包括字段、索引、約束等),但不復制數據。
數據篩選插入:使用 INSERT INTO … SELECT 將源表中符合條件的數據插入新表。
實例
場景:從 employees 表復制 2023 年入職的員工到新表 employees_2023。
sql
– 1. 創建結構相同的新表
mysql> CREATE TABLE employees_2023 LIKE employee;
Query OK, 0 rows affected (0.04 sec)
– 2. 插入符合條件的數據
INSERT INTO employees_2023
SELECT *
FROM employee
WHERE hire_date >= ‘2023-01-01’ AND hire_date < ‘2024-01-01’;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
關鍵點:
新表 employees_2023 包含與 employees 相同的字段、索引和約束。
SELECT * 表示復制所有字段,需確保源表與目標表結構完全一致。
二、CREATE TABLE … AS SELECT
原理
結構與數據一次性創建:根據 SELECT 子句的字段動態創建新表,并將查詢結果直接插入。
新表結構:僅包含 SELECT 中顯式指定的字段,不繼承源表的索引和約束(除非手動聲明)。
實例
場景:創建 high_salary_employees 表,僅包含高薪員工的姓名和薪資。
sql
CREATE TABLE high_salary_employees AS
SELECT
emp_no, – 顯式指定字段
first_name+last_name,
salary
FROM employee
WHERE salary > (SELECT AVG(salary) FROM employee); – 篩選高薪員工
關鍵點:
新表 high_salary_employees 僅包含 emp_id、full_name、salary 三個字段。
不繼承源表的索引和約束,如需需手動添加(如 PRIMARY KEY)。
三、兩種方法對比
特性 CREATE TABLE … LIKE + INSERT CREATE TABLE … AS SELECT
結構完整性 完全復制源表結構(含索引、約束) 僅復制 SELECT 中指定的字段
數據篩選靈活性 支持復雜 WHERE 條件和多表連接 支持 WHERE,但需提前規劃字段列表
性能(大數據量) 分兩步執行,可能稍慢 一次性完成,通常更快
適用場景 需要完整保留源表結構,后續可能修改數據 快速創建臨時表或統計結果表
四、注意事項
字段匹配:
使用 INSERT INTO … SELECT 時,SELECT 的字段順序和類型必須與目標表嚴格一致。
示例(指定字段避免順序問題):
sql
INSERT INTO employees_2023 (emp_id, full_name, hire_date)
SELECT id, name, hired_at FROM employees WHERE …;
約束與索引:
CREATE TABLE … AS 不會復制源表的約束(如 NOT NULL)和索引,需手動添加:
sql
CREATE TABLE high_salary_employees AS
SELECT emp_id, salary FROM employees WHERE …;
ALTER TABLE high_salary_employees ADD PRIMARY KEY (emp_id); – 手動添加主鍵
臨時表優化:
若需快速統計,可結合 TEMPORARY 關鍵字:
sql
CREATE TEMPORARY TABLE temp_stats AS
SELECT dept_id, COUNT(*) FROM employees GROUP BY dept_id;
五、實戰案例
需求:從 orders 表復制 2023 年 1 月的訂單到新表,并添加額外統計字段。
sql
– 方法一:LIKE + INSERT
CREATE TABLE jan2023_orders LIKE orders;
INSERT INTO jan2023_orders
SELECT *
FROM orders
WHERE order_date BETWEEN ‘2023-01-01’ AND ‘2023-01-31’;
– 方法二:AS SELECT(帶計算字段)
CREATE TABLE jan2023_orders_stats AS
SELECT
order_id,
customer_id,
amount,
amount * 0.9 AS discounted_amount – 計算字段
FROM orders
WHERE order_date BETWEEN ‘2023-01-01’ AND ‘2023-01-31’;
通過上述方法,你可以靈活復制表結構和數據,滿足不同場景需求。
https://www.modb.pro/db/408221
MySQL 樣例數據庫 Employee 的制作過程