MySQL數(shù)據(jù)庫表的CRUD操作
一、insert
語法:
INSERT [INTO] table_name [(column [, column] ...)] #列字段 VALUES (value_list) [, (value_list)] ... #列字段的內(nèi)容 value_list: value, [, value] ...
案例:
-- 創(chuàng)建一張學生表 CREATE TABLE students ( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, sn INT NOT NULL UNIQUE COMMENT '學號', name VARCHAR(20) NOT NULL, qq VARCHAR(20) );
1. 單行數(shù)據(jù) - 全列插入 + 指定列插入
- 指定列插入:列字段和列字段的內(nèi)容一定要一一匹配
insert into student (sn, name, qq) values (123, '張飛', '12345');
- 全列插入:全列插入有兩種方式,一個是省略
values
左側字段名,一個是都指定
insert into students values (10, 124, '關羽', '13245'); insert into students (id, sn, name, qq) values (14, 125, '劉備', '14525');
可以省略 into
insert students (sn, name, qq) values (126, '諸葛亮', '12525');
2. 多行數(shù)據(jù) - 全列插入 + 指定列插入
指定列多行插入
insert students (sn, name, qq) values (127, '曹操', '15256'), (128, '許攸', '23445');
全列多行插入
insert students values (20, 129, '孫權', '12256'), (21, 130, '呂布', '33445');
3. 插入否則更新
由于 主鍵 或者 唯一鍵 對應的值已經(jīng)存在而導致插入失敗。
但我就是想讓它先確認是不是在數(shù)據(jù)庫中存在,不存在就插入,存在不要攔我然后執(zhí)行后面的修改語句。
選擇性的進行同步更新操作 語法:
INSERT ... ON DUPLICATE KEY UPDATE column = value [, column = value] ...
如果不存在就插入,存在發(fā)生主鍵或者唯一鍵沖突不要報錯,接著執(zhí)行后面的修改語句。
insert into students values (14, 111, '周瑜', '56321') on duplicate key update sn=111, name='周瑜', qq=56321;
注意更新的值不能和其他的主鍵和唯一鍵沖突,否則不能更新。
0 row affected:表中有沖突數(shù)據(jù),但沖突數(shù)據(jù)的值和 update 的值相等
1 row affected:表中沒有沖突數(shù)據(jù),數(shù)據(jù)被插入
2 row affected:表中有沖突數(shù)據(jù),并且數(shù)據(jù)已經(jīng)被更新
通過 MySQL 函數(shù)獲取受到影響的數(shù)據(jù)行數(shù)
mysql> select row_count(); +-------------+ | row_count() | +-------------+ | -1 | +-------------+ 1 row in set (0.00 sec)
4. 替換
主鍵或者唯一鍵沒有沖突,則直接插入,如果沖突,則 刪除后再插入(replace into)
mysql> insert into students values (22, 31,'Mike', '9856'); Query OK, 1 rows affected (0.00 sec) mysql> select * from students; +----+----+------+------+ | id | sn | name | qq | +----+----+------+------+ | 22 | 31 | Mike | 9856 | +----+----+------+------+ mysql> REPLACE INTO students (sn, name, qq) values (31, 'Tom', '9856'); Query OK, 2 rows affected (0.00 sec) mysql> select * from students; +----+----+------+------+ | id | sn | name | qq | +----+----+------+------+ | 23 | 31 | Tom | 9856 | +----+----+------+------+
- 1 row affected: 表中沒有沖突數(shù)據(jù),數(shù)據(jù)被插入
- 2 row affected: 表中有沖突數(shù)據(jù),刪除后重新插入
- 這里從
id
就可以看到是刪除后插入的,因為id
是自增的,剛才是 22,現(xiàn)在是 23 了。
二、Retrieve
語法:
SELECT [DISTINCT] {* | {column [, column] ...} [FROM table_name] # 從那個表篩選 [WHERE ...] # 篩選條件 [ORDER BY column [ASC | DESC], ...] # 對篩選結果排序 LIMIT ... # 限定篩選出來的條數(shù)
distinct:對內(nèi)容進行去重
- *:全列查詢
- column,column…:指定列查詢
案例:
-- 創(chuàng)建表結構 CREATE TABLE exam_result ( id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20) NOT NULL COMMENT '同學姓名', chinese float DEFAULT 0.0 COMMENT '語文成績', math float DEFAULT 0.0 COMMENT '數(shù)學成績', english float DEFAULT 0.0 COMMENT '英語成績' ); -- 插入測試數(shù)據(jù) INSERT INTO exam_result (name, chinese, math, english) VALUES ('唐三藏', 67, 98, 56), ('孫悟空', 87, 78, 77), ('豬悟能', 88, 98, 90), ('曹孟德', 82, 84, 67), ('劉玄德', 55, 85, 45), ('孫權', 70, 73, 78), ('宋公明', 75, 65, 30);
1. select 列
全列查詢通常情況下不建議使用 *
進行全列查詢查詢的列越多,意味著需要傳輸?shù)臄?shù)據(jù)量越大;可能會影響到 索引 的使用
select * from exam_result;
指定列查詢指定列的順序不需要按定義表的順序來
select id, name, chinese from exam_result;
查詢字段為表達式 select
非常特殊,后面可以跟 select
自帶的子句,篩選條件等,也可以跟 表達式
- 為查詢結果 指定別名 語法:
SELECT column [AS] alias_name [...] FROM table_name; # 這里 as 可以不帶
- 結果去重
select distinct math from exam_result;
2. where 條件
- 剛剛是對表的整體信息做篩選,但是實際在做查詢的時候一定有篩選條件。
- 按條件篩選影響的是未來顯示出來信息的條目數(shù)或者說是行數(shù),以前是按列位單位把全部行都拿出來了。
- 如果一列想拿那些行由
where
條件來決定。
where
是篩選子句,后面可以跟特定的比較運算符來決策我們應該如何進行篩選,
where
就有點像C/C++里面的 if 語句,根據(jù)后面條件進行判斷。
?? 比較運算符:
運算符 | 說明 |
---|---|
>, >=, <, <= | 大于,大于等于,小于,小于等于 |
= | 等于,NULL 不安全,例如 NULL = NULL 的結果是 NULL |
<=> | 等于,NULL 安全,例如 NULL <=> NULL 的結果是 TRUE(1) |
!=, <> | 不等于 |
value BETWEEN a0 AND a1 | 范圍匹配,[a0, a1],如果 a0 <= value <= a1,返回 TRUE(1) |
IN (option, …) | 如果是 option 中的任意一個,返回 TRUE(1) |
IS NULL | 是 NULL |
IS NOT NULL | 不是 NULL |
LIKE | 模糊匹配。% 表示任意多個(包括 0 個)任意字符;_ 表示任意一個字符 |
?? 注意事項
=
時兩側進行null
值比較,是不能參與運算的- 如果想判斷
null
是否相等 使用<=>
- 不過一般也不這樣去判斷,一般更喜歡用
IS NULL
去判斷一個值是否是null
?? 邏輯運算符:
運算符 | 說明 |
---|---|
AND | 多個條件必須都為 TRUE(1),結果才是 TRUE(1) |
OR | 任意一個條件為 TRUE(1), 結果為 TRUE(1) |
NOT | 條件為 TRUE(1),結果為 FALSE(0) |
具體案例
- 基于上面的建表,下面只會寫出指令,最終結果為了節(jié)省篇幅就省略了
① 英語不及格的同學名字及英語成績 ( < 60 )
select name, english from exam_result where english < 60;
**② **語文成績在 [80, 90] 分的同學及語文成績 使用 AND
進行條件連接
select name, chinese from exam_result where chinese >= 80 and chinese <= 90;
使用 BETWEEN … AND …
條件
select name, chinese from exam_result where chinese between 80 and 90;
③ 數(shù)學成績是 58 或者 59 或者 98 或者 99 分的同學及數(shù)學成績使用 OR
進行條件連接,滿足任意一個就為真
select name, math from exam_result where math = 58 or math = 59 or math = 98 or math = 99;
使用 IN
條件,滿足 () 里任意一個就為真
select name, math from exam_result where math in (58, 59, 98, 99);
- 姓孫的同學 及 孫某同學 有時候匹配并不給具體值的更細節(jié)的字段含義,可能就只給一個模糊搜索的關鍵字。就如上面。反正條件不給全就給一個模糊的條件。
- 我們就可以用
LIKE
模糊匹配%
匹配任意多個(包括 0 個)任意字符注意MySQL
可以用 ‘ ’ 或者 “ ” 表示字符串
select name from exam_result where name like '孫%';
_
匹配嚴格的一個任意字符:
select name from exam_result where name like '孫_';
④ 語文成績好于英語成績的同學
select name, chinese, english from exam_result where chinese > english;
⑤ 總分在 200 分以下的同學
mysql> select name, math + chinese + english total from exam_result where math + chinese + english < 200; +-----------+-------+ | name | total | +-----------+-------+ | 劉玄德 | 185 | | 宋公明 | 170 | +-----------+-------+ # 但是寫成這樣就會有問題 mysql> select name, math + chinese + english as total from exam_result where total < 200; ERROR 1054 (42S22): Unknown column 'total' in 'where clause'
為啥這里它報錯了未知列total,我們不是做過重命名嗎。這個total不是已經(jīng)有了嗎,怎么這里報不知道total呢?
解釋如下:
- 很簡單,我們一定是先執(zhí)行
from
,在執(zhí)行where
,然后在執(zhí)行select
- 篩選后再執(zhí)行,從 1 中帶著 2 去3中篩選
- **原因:**只把小于操作 2 的相加后再打印,更節(jié)省空間
- 所以不可以在 where 中使用重命名
⑥ 語文成績 > 80 并且不姓孫的同學
AND
與 NOT
的使用
select name, chinese from exam_result where chinese>80 and name not like '孫%';
⑦ 孫某同學,否則要求總成績 > 200 并且 語文成績 < 數(shù)學成績 并且 英語成績 > 80
要么就是孫某同學,要么就得滿足后面的一堆要求,總共就兩個條件,在mysql如果條件很多可以用()把這個條件括起來,表示一個單元
select name, chinese, math, english, chinese + math + english total from exam_result where name like '孫_' or (chinese + math + english > 200 and chinese < math and english > 80);
3. 結果排序 – order by
語法:
SELECT ... FROM table_name [WHERE ...] ORDER BY column [ASC|DESC], [...];
- ASC 為升序(從小到大)(ascending)
- DESC 為降序(從大到?。?descding)
- 默認為 ASC
注意:沒有 ORDER BY 子句的查詢,返回的順序是未定義的,永遠不要依賴這個順序
【案例】
- 基于上面建的表來操作
yi同學及數(shù)學成績,按數(shù)學成績升序顯示
select name, math from exam_result order by math asc;
- 注意:
NULL
視為比任何值都小,升序出現(xiàn)在最上面
② 查詢同學各門成績,依次按 數(shù)學降序,英語升序,語文升序的方式顯示
select name, math, english, chinese from exam_result order by math desc, english, chinese;
③ 查詢同學及總分,由高到低
select name, chinese + math + english total from exam_result order by total desc;
- 欸,看到這里有個問題 ? 為什么在order by這里可以使用別名進行排序,而where后面沒有辦法使用別名?
因此可以得到一個結論:能不能用別名完全是取決于當前sql中子句的執(zhí)行順序!
- 你要對表結構的數(shù)據(jù)進行排序,一定是得先有數(shù)據(jù)!
- 有人可能說不是表結構不就天然有數(shù)據(jù)嗎,因此就直接可以把表結構數(shù)據(jù)全排完,然后在選行不行,但我們肯定不會愿意這樣 浪費時間處理數(shù)據(jù)排序
- 因為你沒有篩選,在排序的時候一定有大批數(shù)據(jù)其實是不需要排序的,而對這些數(shù)據(jù)排序本身就是浪費空間和時間,mysql沒有這么笨!
- 所以會先篩選
select
再排序order by
4. 篩選分頁 – limit
什么是分頁呢?
- 如果一個表中數(shù)據(jù)量太大,這個時候如果全列查詢就有一大堆,這樣不便于查看分析
- 有時候我們不想一次顯示這么多,因此我們就可以對結果進行
LIMIT
分頁。
limit
本身沒有篩選功能,只是 按照它后面跟的數(shù)字 把要顯示的結果按照 起始位置 和 步長,給我們顯示多條記錄。
語法:
-- 起始下標為 0 -- 從 s 開始,篩選 n 條結果 SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT s, n -- 從 0 開始,篩選 n 條結果 SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT n; -- 從 s 開始,篩選 n 條結果,比第二種用法更明確,建議使用 SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT n OFFSET s;
建議: 對未知表進行查詢時,最好加一條 LIMIT 1
,避免因為表中數(shù)據(jù)過大,查詢?nèi)頂?shù)據(jù)導致數(shù)據(jù)庫卡死。
- 默認從 0 下標開始,篩選多條記錄。
- limit 分頁讀取的執(zhí)行順序,是在最后的
- 也可以指定下標開始篩選后面跟的是步長。從指定位置開始,連續(xù)讀取多條記錄。
如下:
mysql> select id, name, math from exam_result order by id limit 3 offset 0; +----+-----------+------+ | id | name | math | +----+-----------+------+ | 1 | 唐三藏 | 98 | | 2 | 孫悟空 | 78 | | 3 | 豬悟能 | 98 | +----+-----------+------+ mysql> select id, name, math from exam_result order by id limit 3 offset 6; +----+-----------+------+ | id | name | math | +----+-----------+------+ | 7 | 宋公明 | 65 | +----+-----------+------+
LIMIT
后面跟的是篩選幾行,OFFSET
后面跟的是從那行開始。limit
可以進行分頁。就比如數(shù)據(jù)多就可以這樣進行 分頁讀
關鍵字執(zhí)行順序總結
- **from > on> join > where > group by > with > having > select(**含重命名) > distinct > order by > limit
三、Update | Delete | 插入查詢結果
3.1 Update
語法:
UPDATE table_name SET column = expr [, column = expr ...] [WHERE ...] [ORDER BY ...] [LIMIT ...]
set
后面跟的是要重新設定的值,可以是多列。- 一般在
update
的時候必須采用對應where
子句進行條件篩選,如果沒有的話會把這個表中指定的列全部都更新,這是不合理的。
【案例】:基于上面創(chuàng)建的 exam_result 表
對查詢到的結果進行列值更新: set
① 將孫悟空同學的數(shù)學成績變更為 80 分
update exam_result set math=80 where name='孫悟空';
② 將曹孟德同學的數(shù)學成績變更為 60 分,語文成績變更為 70 分
update exam_result set math=60, chinese=70 where name='曹孟德';
③ 將總成績倒數(shù)前三的 3 位同學的數(shù)學成績加上 30 分
- 更新值為原值基礎上變更。
- 注意據(jù)更新,不支持 math += 30 這種語法。
④ 將所有同學的語文成績更新為原來的 2 倍
update exam_result set chinese=chinese*2;
注意:更新全表的語句慎用!
3.2 Delete
語法:
DELETE FROM table_name [WHERE ...] [ORDER BY ...] [LIMIT ...]
- 一般都是拿著條件刪除 where
- 不加條件就是把整表的內(nèi)容刪除了,不過表結構還在。
- 刪表結構drop
比如刪除之前 exam_result 中的孫悟空的成績,如下:
delete from exam_result where name='孫悟空';
我們再來個測試,測試表 如下:
-- 準備測試表 create table for_delete(id int primary key auto_increment, name varchar(20)); -- 插入測試數(shù)據(jù) INSERT INTO for_delete (name) VALUES ('A'), ('B'), ('C'); -- 查詢表數(shù)據(jù) select * from for_delete; +----+------+ | id | name | +----+------+ | 1 | A | | 2 | B | | 3 | C | +----+------+
現(xiàn)在我們可以看到id設置了自增,目前已經(jīng)插入三條記錄了,如果在插入一條記錄這個id就是4了。
但我們現(xiàn)在不插直接把表刪除,如下:
-- 刪除表 delete from for_delete; mysql> show create table for_delete \G; *************************** 1. row *************************** Table: for_delete Create Table: CREATE TABLE `for_delete` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec) mysql> select last_insert_id(); +------------------+ | last_insert_id() | +------------------+ | 1 | +------------------+ -- 插入新數(shù)據(jù) insert into for_delete(name) values('E'); mysql> select * from for_delete; +----+------+ | id | name | +----+------+ | 4 | E | +----+------+
當新插入一條記錄時這個id是4,并且自增長已經(jīng)變成下一個id值了
- 說明
delete from
清空表 的方式不會將 自增值置 0
清空表還有一種做法叫做 截斷表。在效果和 delete
一模一樣,但是在細節(jié)和原理是有差別的。
截斷表
語法:
TRUNCATE [TABLE] table_name
注意:這個操作慎用
- 只能對整表操作,不能像
DELETE
一樣針對部分數(shù)據(jù)操作; - 實際上 MySQL 不對數(shù)據(jù)操作,所以比
DELETE
更快,但是TRUNCATE
在刪除數(shù)據(jù)的時候,并不經(jīng)過真正的事物,所以無法回滾 - 會重置
AUTO_INCREMENT
項
【案例】:
mysql> select * from for_delete; # 操作前 +----+------+ | id | name | +----+------+ | 4 | E | +----+------+ -- 插入 insert into for_delete(name) values('A'), ('B'), ('C'); -- truncate 操作 mysql> truncate for_delete; Query OK, 0 rows affected (0.04 sec) mysql> insert into for_delete(name) values('E'); Query OK, 1 row affected (0.01 sec) mysql> select * from for_delete; # 操作后 +----+------+ | id | name | +----+------+ | 1 | E | +----+------+
- 可以看到表結構還在,但是內(nèi)容已經(jīng)被清空了。但是這里值得注意的一點是,之前自增長是5,現(xiàn)在
truncata
清空表后自增長已經(jīng)沒有了。 - 然后新插一條記錄,id變成1了。自增長 變成 2 了
- 換句話說
truncate
會重置自增長。而delete
并不會。
實際上,TRUNCATE
和 DELETE
還存在一些差異。TRUNCATE
操作是直接將表中的數(shù)據(jù)清空,并且這個操作不通過事務處理。而 DELETE
和其他 SQL 操作則會在執(zhí)行時被包裝進 事務 中,再由 MySQL 處理。
事務的影響
事務 的使用與否會影響 MySQL 對操作信息的記錄方式。MySQL 使用其自身的 日志系統(tǒng) 來記錄數(shù)據(jù)操作的信息,主要包括以下幾種 日志:
- bin.log:存儲經(jīng)過優(yōu)化的歷史 SQL 語句。
- redo.log:用于在 MySQL 遭遇宕機時能夠恢復數(shù)據(jù)。
- undo.log:用于存儲回滾段信息。
日志的作用
bin.log
記錄的是歷史 SQL 語句,并支持 MySQL 的主從同步機制。當一個數(shù)據(jù)庫執(zhí)行完某些操作后,可以通過bin.log
將這些 SQL 同步到另一個數(shù)據(jù)庫,從而使兩個數(shù)據(jù)庫的數(shù)據(jù)保持一致(主從同步), 需要注意,默認情況下bin.log
是 關閉 的。redo.log
在 MySQL 遇到故障時 提供數(shù)據(jù)恢復功能
持久化方式
持久化方式指的是為了能夠在系統(tǒng)崩潰后快速恢復數(shù)據(jù)庫數(shù)據(jù) 的方法。
將數(shù)據(jù)以文件的形式寫入磁盤,通常有兩種方式
- 記錄歷史sql語句
- 記錄數(shù)據(jù)本身
Truncate的特點
由于 TRUNCATE
不記錄自己的操作到 日志 中,也不將其作為 事務 的一部分,因此它僅是簡單地清空表中的數(shù)據(jù),這樣做的結果是 TRUNCATE
的執(zhí)行速度較快。
TRUNCATE
因為其非事務性及不記錄日志的特點,在執(zhí)行速度上有優(yōu)勢- 但在數(shù)據(jù)恢復和一致性方面不如
DELETE
3.3 插入查詢結果
語法:
INSERT INTO table_name [(column [, column ...])] SELECT ...
我們要插就插,要刪就刪,要改就改,要查就查,實際我們也可以將select和insert組合。可以把數(shù)據(jù)從其他表里面篩選出來,然后插入到另一個表里面。
我們來實現(xiàn)如下一個小實驗:
刪除表中的重復記錄,重復的數(shù)據(jù)只能有一份,現(xiàn)在我們有如下的一個表:
mysql> select * from duplicate_t; +------+------+ | id | name | +------+------+ | 1 | a | | 1 | a | | 2 | b | +------+------+
我的做法是
創(chuàng)建一個和原表一樣結構的空表
no_duplicate_t
,從原始表中把去重之后的結果篩選出來插入到
no_duplicate_t
這個表不就是不重復的嘛然后對
duplicate_t
重命名,no_duplicate_t
改名字為duplicate_t
。最終不就完成了對duplicate_t
去重
mysql> create table no_duplicate_t like duplicate_t; # 創(chuàng)建完全一樣的表,用 like mysql> insert into no_duplicate_t select distinct * from duplicate_t; # 全列插入就不用指定列 -- 重命名 mysql> rename table duplicate_t to old_duplicate_t; mysql> rename table no_duplicate_t to duplicate_t; mysql> select * from duplicate_t; # 查詢最終結果 +------+------+ | id | name | +------+------+ | 1 | a | | 2 | b | +------+------+
?這里有個細節(jié)問題,為什么最后是通過 rename
方式進行的?
如果今天想把一個文件上傳到 linux
上,比如這個文件是1G上傳時間可能是10分鐘,我們想把這個文件上傳號之后放到一個目錄下,并且要求它是為 原子性方式 放入的。
- 所以一般我們不能直接把文件上傳到對應的目錄下,因為它上傳的過程一種在寫入一定不是 原子 ,它太慢了。
- 所以我們把這個文件上傳到臨時目標下,全部上傳之后然后再把文件
move
到那個目錄下。 - 直接
move
這個動作實際上是 原子的 ,其實對一個文件進行 重命名 也是同一個道理
所以我們最后通過 rename
方式,就是單純的想等一切都就緒了,然后統(tǒng)一放入,更新,生效等! 和冗長的其他動作相比,這個動作非常輕。
到此這篇關于MySQL數(shù)據(jù)庫表的CRUD操作的文章就介紹到這了,更多相關MySQL 表CRUD操作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Mysql注入中的outfile、dumpfile、load_file函數(shù)詳解
這篇文章主要介紹了Mysql注入中的outfile、dumpfile、load_file,需要的朋友可以參考下2018-05-05MySQL中replace into與replace區(qū)別詳解
本文主要介紹了MySQL中replace into與replace區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-08-08MySQL數(shù)據(jù)庫主機127.0.0.1與localhost區(qū)別
這篇文章主要介紹了MySQL主機127.0.0.1與localhost區(qū)別總結,需要的朋友可以參考下2018-06-06SQL實現(xiàn)LeetCode(196.刪除重復郵箱)
這篇文章主要介紹了SQL實現(xiàn)LeetCode(196.刪除重復郵箱),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-08-08