描述
牛客后臺會記錄每個用戶的試卷作答記錄到exam_record表,現在有兩個用戶的作答記錄詳情如下:
- 用戶1001在2021年9月1日晚上10點11分12秒開始作答試卷9001,并在50分鐘后提交,得了90分;
- 用戶1002在2021年9月4日上午7點1分2秒開始作答試卷9002,并在10分鐘后退出了平臺。
試卷作答記錄表exam_record中,表已建好,其結構如下,請用一條語句將這兩條記錄插入表中。
Filed | Type | Null | Key | Extra | Default | Comment |
id | int(11) | NO | PRI | auto_increment | (NULL) | 自增ID |
uid | int(11) | NO | (NULL) | 用戶ID | ||
exam_id | int(11) | NO | (NULL) | 試卷ID | ||
start_time | datetime | NO | (NULL) | 開始時間 | ||
submit_time | datetime | YES | (NULL) | 提交時間 | ||
score | tinyint(4) | YES | (NULL) | 得分 |
該題最后會通過執行SELECT uid, exam_id, start_time, submit_time, score FROM exam_record;來對比結果
INSERT INTOexam_record (uid, exam_id, start_time, submit_time, score)
VALUES('1001','9001','2021-09-01 22:11:12','2021-09-01 23:01:12','90');
INSERT INTOexam_record (uid, exam_id, start_time)
VALUES('1002','9002','2021-09-04 07:01:02');
SQL?INSERT INTO
?語句:插入記錄的不同方式
INSERT INTO
語句是 SQL 中用于向數據庫表中添加新記錄(行)的核心命令。根據需要插入的數據完整性、目標列的指定方式以及數據來源,有多種使用方式。
1. 完整插入 (指定所有列)
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
- 說明:?明確指定要插入數據的所有列名(或大部分關鍵列),并在?
VALUES
?子句中提供對應順序的值。 - 優點:?清晰、安全、可讀性強。即使表結構后續有變動(如新增列),只要新列有默認值或允許?
NULL
,此語句通常仍能正常執行。 - 缺點:?需要寫出所有列名,代碼稍長。
- 分析:?明確指定了?
exam_record
?表的?uid
,?exam_id
,?start_time
,?submit_time
,?score
?這5個列,并提供了對應的值。這是一次完整的考試記錄插入,包含了開始時間、提交時間和得分。 - 示例
INSERT INTOexam_record (uid, exam_id, start_time, submit_time, score) VALUES('1001','9001','2021-09-01 22:11:12','2021-09-01 23:01:12','90');
2. 部分插入 (指定部分列)
INSERT INTO table_name (column1, column2, ...) -- 只列出需要賦值的列
VALUES (value1, value2, ...);
- 說明:?只指定需要插入數據的部分列名。未指定的列將根據其定義被賦予默認值(如?
DEFAULT
?約束)、NULL
(如果允許),或者如果該列是?AUTO_INCREMENT
?主鍵,會自動生成下一個值。 - 優點:?靈活,當某些列的值可以由數據庫自動生成或可以為空時,無需手動指定。
- 缺點:?需要清楚了解表結構和各列的約束(如?
NOT NULL
、默認值等),否則可能因缺少必要值而插入失敗。 - 分析:?只指定了?
uid
,?exam_id
,?start_time
?三個列。submit_time
?和?score
?列未指定。 - 結果:?
submit_time
?很可能為?NULL
(表示考試尚未提交),score
?也為?NULL
(或0,取決于表設計)。這通常用于記錄用戶開始考試的事件,最終成績和提交時間將在考試結束后更新。 - 示例
INSERT INTOexam_record (uid, exam_id, start_time) VALUES('1002','9002','2021-09-04 07:01:02');
3. 省略列名列表的插入 (不推薦)
語法:
INSERT INTO table_name
VALUES (value1, value2, value3, ...); -- 值的順序必須嚴格匹配表的列順序
- 說明:?省略?
()
?中的列名列表。VALUES
?中的值必須嚴格按照表定義的列順序提供,且數量必須完全匹配。 - 優點:?代碼最短。
- 缺點:
- 極易出錯:?一旦表結構改變(如增刪列、調整列序),此語句極可能失敗或插入到錯誤的列。
- 可讀性差:?無法直觀看出每個值對應哪個列。
- 靈活性差:?必須為所有列提供值,即使是?
NULL
?或默認值也需要顯式寫出來。
- 結論:?強烈不推薦在生產環境或需要維護的代碼中使用此方式。
4. 插入多行記錄
語法:
INSERT INTO table_name (column1, column2, ...)
VALUES (value1a, value2a, ...),(value1b, value2b, ...),(value1c, value2c, ...);
- 說明:?在一個?
INSERT
?語句中,通過?VALUES
?后跟多組用逗號分隔的?(值)
?來一次性插入多條記錄。 - 優點:?效率高,比執行多條單行?
INSERT
?語句更快,尤其是在處理大量數據時,減少了網絡往返和事務開銷。 - 注意:?所有行的列名列表必須相同。
- 示例:
INSERT INTO exam_record (uid, exam_id, start_time) VALUES ('1003', '9001', '2021-09-05 10:00:00'),('1004', '9001', '2021-09-05 10:05:00'),('1005', '9003', '2021-09-06 14:30:00');
5. 從其他表插入數據 (INSERT INTO ... SELECT
)
語法:
INSERT INTO table_name (column1, column2, ...)
SELECT column1, column2, ...
FROM source_table
WHERE condition;
- 說明:?將一個?
SELECT
?查詢的結果集直接插入到目標表中。 - 優點:?強大且高效,適用于數據遷移、備份、根據條件復制數據等場景。
- 注意:?
SELECT
?查詢返回的列數和數據類型必須與?INSERT INTO
?指定的列兼容。 - 示例 (假設要將已完成的考試記錄歸檔):
INSERT INTO exam_archive (uid, exam_id, start_time, submit_time, score) SELECT uid, exam_id, start_time, submit_time, score FROM exam_record WHERE submit_time IS NOT NULL AND score IS NOT NULL; -- 假設已提交且有成績
6. 替換插入 (REPLACE INTO
)
語法:
REPLACE INTO table_name [(column1, column2, ...)]
VALUES (value1, value2, ...);
- 說明:?這是?MySQL?特有的擴展語句。它嘗試插入新行,如果新行與現有行在主鍵或唯一索引上發生沖突,則先刪除舊行,再插入新行。
- 核心邏輯:?
REPLACE INTO
?=?DELETE
?(沖突行) +?INSERT
?(新行)。 - 優點:
- 簡化邏輯:?一行代碼實現“存在則替換,不存在則插入”。
- 原子性:?操作通常是原子的。
- 缺點:
- 性能開銷:?“刪除+插入”比?
UPDATE
?開銷大。 - 主鍵變更:?自增主鍵會獲得新值,可能影響外鍵引用。
- 非標準:?僅 MySQL/MariaDB 支持,可移植性差。
- 性能開銷:?“刪除+插入”比?
- 示例:
REPLACE INTO examination_info VALUES(NULL, 9003, "SQL", "hard", 90, "2021-01-01 00:00:00");
- 分析:?假設?
exam_id=9003
?是唯一鍵。- 若?
exam_id=9003
?不存在:直接插入,自增主鍵獲新值。 - 若?
exam_id=9003
?已存在:先刪除舊記錄,再插入新記錄,自增主鍵會變成一個新值。
- 若?
- 分析:?假設?
總結與最佳實踐
- 明確指定列名:?始終使用?
INSERT INTO table_name (col1, col2, ...)
?的形式,避免省略列名列表。這能確保代碼的健壯性和可維護性。 - 利用部分插入:?當某些列的值可以由數據庫自動處理(如?
AUTO_INCREMENT
、DEFAULT
、NULL
)時,使用部分插入是合理且常見的做法(如你的第二個示例)。 - 批量插入:?當需要插入多條記錄時,優先考慮使用單條?
INSERT
?語句插入多行,以提高性能。 - 數據來源:?除了直接提供值 (
VALUES
),也要熟悉?INSERT ... SELECT
?這種從查詢結果插入數據的強大方式。 - 注意數據類型:?確保?
VALUES
?或?SELECT
?中的值與目標列的數據類型兼容。你的示例中使用了單引號包裹字符串和日期時間,這是正確的做法。對于數值類型(如?score
),通常不需要引號,但加上引號(如?'90'
)在多數數據庫中也會被隱式轉換,不過最好遵循數據類型規范。