Ø 簡介
本文介紹 Oracle 中的增刪改語句,即 INSERT、DELETE、UPDATE 語句的使用。是時候展現真正的技術了,快上車:
1. 插入數據(INSERT)
2. 修改數據(UPDATE)
3. 刪除數據(DELETE)
4. 使用 MERGE INTO 語句完成增刪改操作
5. 回滾(rollback)的使用
6. 注意事項
1. 插入數據(INSERT)
u 語法:
INSERT INTO TABLE_NAME [(column1[, column2, …]] VALUES(value1[, value2, …]);
說明:
1) INSERT 數據時可以指定列名,也可不指定列名。如果不指定列名,必須為每一列都提供數據,並且順序必須與列名的順序一致;如果指定列名,提供的數據需要與指定的列名順序一致;
2) 插入數據時數字類型的列可直接寫入,字符或日期類型的列需要加單引號;
3) 插入的數據必須滿足約束規則,主鍵和 NOT NULL 的列必須提供數據。
u 插入數據的方式
1) 首先,可以在 PL/SQL Developer 中使用 FOR UPDATE 語句
1. 首先執行 SELECT 語句
SELECT * FROM Table01 FOR UPDATE;
2. 點擊鎖表按鈕
3. 編輯數據 -> 記入改變 -> 表解鎖按鈕
4. 最后點擊提交
l 說明:低版本的 PL/SQL Developer 操作與以上類似。
2) 使用 INSERT INTO 語句,插入一條數據
INSERT INTO Table01(Id, Name) VALUES(2, '李四'); --指定所有列
COMMIT; --必須執行提交命令
提示:在平常開發中,建議顯示指定插入的列名,有助於提高代碼的可讀性。
INSERT INTO Table01(Id) VALUES(3); --指定部分列,其他未指定的列表必須可以為空(即 NULL)
COMMIT;
INSERT INTO Table01 VALUES(4, '王五'); --不指定任何列,必須按順序插入所有列
COMMIT;
3) 使用 INSERT INTO SELECT 語句,插入多條數據
INSERT INTO Table02 SELECT * FROM Table01; --將 Table01 中的所有數據插入 Table02 中(注意:可以指定插入的列;Table02 必須存在;可指定 Table01 的查詢條件)
COMMIT;
4) 另外,還可以使用 PL/SQL Developer 中使用變量的方式(該方式不怎么實用,不做詳細介紹)
INSERT INTO Table01 VALUE(&Id, &Name);
5) 同時插入多條(支持多表插入)
INSERT ALL
INTO Table01 VALUES(10, '張10')
INTO Table01 VALUES(11, '張11')
INTO Table02 VALUES(20, '李20') --同時插入 Table02
SELECT * FROM DUAL;
COMMIT;
注意:
1. INSERT ALL INTO 在效率上,比逐條執行 INSERT INTO 語句要高很多;
2. 在使用 INSERT ALL INTO 語句插入數據時,對於主鍵使用序列插入式,多條 INTO 會違反約束條件(即對於同一個序列的多條 INTO 會產生相同的序列號),所以使用序列插入時,並不適用使用 INSERT ALL INTO 同時插入多條數據!
n 注意事項:
1. 在插入數值(number)和字符(char)類型時,Oracle 支持數值與字符相互轉換,例如:
字符轉數值:
INSERT INTO Tab01(id) VALUES('12a'); --ORA-01722:無效數字
INSERT INTO Tab01(id) VALUES('123'); --插入成功,結果為123
INSERT INTO Tab01(id) VALUES('456.56'); --插入成功,結果為457(四舍五入)
數值轉字符:
INSERT INTO Tab01(name) VALUES(123); --插入成功,結果為123
INSERT INTO Tab01(name) VALUES(123.56); --插入成功,結果為123.56
提示:雖然 Oracle 支持這種轉換,但是並不建議使用該方式去寫入數據,不利於理解和閱讀。
2. 插入字符類型字段時,超過指定長度直接報錯,例如:
CREATE TABLE Tab02(name varchar2(2) NOT NULL);
INSERT INTO Tab02(name) VALUES('abcd'); --插入失敗(並不會截斷,而是直接報錯)
INSERT INTO Tab02(name) VALUES('ab'); --插入成功,結果為ab
3. 插入字符和日期類型時,必須加上單引號,例如:'中國', '22-08-2018'。
4. 插入的字符類型可以為空(NULL)時,也可以指定為空字符串,例如:
CREATE TABLE Tab03(id number(3) NOT NULL, name varchar2(10) NULL);
INSERT INTO Tab03(id, name) VALUES(1, null); --插入成功,結果為NULL
INSERT INTO Tab03(id, name) VALUES(2, ''); --插入成功,結果也為NULL
INSERT INTO Tab03(id, name) VALUES(3, ' '); --插入成功,結果為' '
SELECT * FROM Tab03 WHERE name IS NULL;
SELECT t.*, dump(name) FROM Tab03 t;
由以上兩個查詢可以看出,在 Oracle 中對於字符類型,''(空字符串)也將以 NULL 對待,即:空字符串就是 NULL, NULL 也是空字符串。
5. 插入 DATE 類型的字段時,需要對日期格式進行轉換,例如:
to_date('1985/10/22', 'yyyy/mm/dd')
2. 修改數據(UPDATE)
u 語法:
UPDATE TABLE_NAME SET column1 = value1[, column2 = value2…] [WHERE 條件];
說明:規則與 INSERT 語句類似。
u 修改數據的方式
1) 同樣,也可以在 PL/SQL Developer 中使用 FOR UPDATE 語句,進行修改操作
SELECT * FROM Table01 FOR UPDATE;
說明:操作步驟與插入數據類似,只是一個是修改原有的數據,一個是新增數據。
2) 使用 UPDATE 語句更新
UPDATE Table01 SET Name='張山' WHERE Id=1; --更新多個字段,使用“,”逗號分隔
COMMIT;
3) 子查詢更新(多列)
UPDATE Table02 SET(Id, Name) = (SELECT Id, Name FROM Table01 WHERE Id=1) WHERE Id=1; --將 Table02 中的 Id, Name 列更新為 Table01 中的 Id, Name,這里沒有其他列,就以 Id 列代替了
COMMIT;
3. 刪除數據(DELETE)
u 語法:
DELETE FROM TABLE_NAME or VIEW_NAME [WHERE <condition>];
注意:刪除數據前,該記錄如果存在外鍵關聯,需要先刪除外鍵表中的關聯數據。
u 刪除數據的方式
1) 同樣,也可以在 PL/SQL Developer 中使用 FOR UPDATE 語句,進行刪除操作
SELECT * FROM Table01 FOR UPDATE;
說明:操作步驟與插入數據類似,點擊“刪除記錄”按鈕即可。
2) 使用 DELETE 語句
DELETE FROM Table01 WHERE Id=3;
COMMIT;
3) 使用 TRUNCATE 語句
TRUNCATE TABLE Table02;
n 注意事項
TRUNCATE 語句具有以下特征:
1. 不能加 WHERE 條件,清除整表數據;
2. 不需要 COMMIT 提交,不支持事務回滾,並且會結束 SAVEPOINT(回滾點);
3. 效率高於 DELETE 語句(速度較快);
4. 不記錄日志,並清除所占用的空間;
5. 不會觸發 DELETE 出發器等特點。
而 DELETE 語句的特征:
1. 可以根據條件刪除數據;
2. 需要顯示 COMMIT 提交,支持事務回滾;
3. 會記錄更新日志,刪除后仍然占用物理空間;
4. 會觸發 DELETE 觸發器等。
4. 使用 MERGE INTO 語句完成增刪改操作
MERGE INTO 是 Oracle 9i 中新增的語句,MERGE 語句可以從一個或多個源表中選擇數據,並將其更新或插入到目標表中。MERGE 語句允許指定條件,以確定是從目標表更新數據還是向目標表中插入數據。到 Oracle 10g 中又對 MERGE INTO 進行了改進,改進如下:
1) UPDATE 或 INSERT 子句可以是可選的;
2) UPDATE 和 INSERT 子句可以加 WHERE 子句;
3) UPDATE 后面可以跟 DELETE 子句來刪除記錄(此時不會更新記錄);
n 完整語法
MERGE INTO target_table
USING source_table
ON search_condition
WHEN MATCHED THEN
UPDATE SET col1 = value1, col2 = value2,...
WHERE <update_condition>
[DELETE WHERE <delete_condition>]
WHEN NOT MATCHED THEN
INSERT (col1,col2,...)
values(value1,value2,...)
WHERE <insert_condition>;
n 示例
1) 單獨使用 THEN UPDATE 子句,將 A 表的數據更新至 B 表
在 SQL Server 中支持以下語法將 A 表的數據更新到 B 表(當然 SQL Server 也是支持 MERGE 語句):
UPDATE Tab04 SET [money]=t5.[money] FROM Tab05 AS t5
WHERE Tab04.id = t5.id; --Tab04 遇到 t5 相同的記錄,只會更新為 t5 第一個記錄的值,並不會報錯
在 Oracle 中不支持以上的更新語法,但可以使用 MERGE INTO 子句來完成,看示例:
--創建表
CREATE TABLE Tab04(id number(3), money number(8,2));
CREATE TABLE Tab05(id number(3), money number(8,2));
--插入數據
TRUNCATE TABLE Tab04;
TRUNCATE TABLE Tab05;
INSERT ALL
INTO Tab04 VALUES(1, 100)
INTO Tab04 VALUES(2, 200)
INTO Tab04 VALUES(6, 600)
INTO Tab04 VALUES(6, 610)
INTO Tab04 VALUES(7, 700)
INTO Tab04 VALUES(9, 900)
INTO Tab05 VALUES(1, 1000)
INTO Tab05 VALUES(2, 2000)
--INTO Tab05 VALUES(2, 2100)
INTO Tab05 VALUES(6, 6000)
INTO Tab05 VALUES(8, 8000)
INTO Tab05 VALUES(9, 9000)
SELECT 1 FROM DUAL;
COMMIT;
--更新數據
MERGE INTO Tab04 t4
USING Tab05 t5 ON(t4.id = t5.id)
WHEN MATCHED THEN UPDATE SET t4.money = t5.money WHERE t1.id < 9; --id=9的記錄將不會更新
--查詢結果
SELECT * FROM Tab04;
注意事項:
1. Tab04 可以被匹配到多條記錄,匹配到多條記錄將一同更新;
2. Tab04 沒有匹配的記錄將不會更新,保持原來的值;
3. Tab05 多條記錄與 Tab04 中匹配時,將報錯:ORA-30926:無法在原表中獲得一組穩定的行(與 SQL Server 不一樣)。因為 MERGE 是確定性語句,所以不能在同一條語句中多次更新目標表的同一行 MERGE。
4. Tab05 的記錄與 Tab04 未匹配時,不會報錯。
當我希望 Tab05 中相同 Id 中金額最大的一條更新到 Tab04 時,可以這樣寫:
MERGE INTO Tab04 t4
USING (SELECT id, MAX(money) money FROM Tab05 GROUP BY id) t5 ON(t4.id = t5.id)
WHEN MATCHED THEN UPDATE SET t4.money = t5.money WHERE t4.id < 9; --加了一個被處理過的派生表(t5)
提示:先取消 --INTO Tab05 VALUES(2, 2100) 的注釋
--再次查詢
SELECT * FROM Tab04;
2) 單獨使用 THEN INSERT 子句,不存在則插入數據
1. 首先,創建目標表,並寫入兩條記錄
CREATE TABLE tar_dept1 AS SELECT * FROM dept WHERE rownum <= 2;
SELECT * FROM tar_dept1;
2. 插入源表的記錄在目標表中不存在的記錄
MERGE INTO tar_dept1 t1
USING dept t2 ON(t1.deptno = t2.deptno)
WHEN NOT MATCHED THEN
INSERT (deptno, dname, loc) VALUES(t2.deptno, t2.dname, t2.loc);
SELECT * FROM tar_dept1;
DROP TABLE tar_dept1; --刪除測試表
3) 同時更新(存在)或插入(不存在)數據
1. 創建目標表,並寫入兩條記錄
CREATE TABLE tar_dept1 AS SELECT * FROM dept WHERE rownum <= 2;
SELECT * FROM tar_dept1;
2. 修改源表中的數據(用於測試)
UPDATE dept SET loc = loc || 'new';
SELECT * FROM dept;
3. 同時更新或插入
MERGE INTO tar_dept1 t1
USING dept t2 ON(t1.deptno = t2.deptno)
WHEN MATCHED THEN
UPDATE SET t1.dname = t2.dname, t1.loc = t2.loc
WHEN NOT MATCHED THEN
INSERT (deptno, dname, loc) VALUES(t2.deptno, t2.dname, t2.loc);
SELECT * FROM tar_dept1;
DROP TABLE tar_dept1; --刪除測試表
4) DELETE WHERE 子句的使用
DELETE 子句一般用的不多,該 DELETE 子句僅刪除目標表中與 ON 和 DELETE WHERE 子句同時匹配的行(此時,將忽略更新語句)。例如,將以上代碼改為下面代碼時,重新執行將得到如下結果:
MERGE INTO tar_dept1 t1
USING dept t2 ON(t1.deptno = t2.deptno)
WHEN MATCHED THEN
UPDATE SET t1.dname = t2.dname, t1.loc = t2.loc
DELETE WHERE t1.deptno > 10 --這里將刪除大於10的記錄,並忽略更新
WHEN NOT MATCHED THEN
INSERT (deptno, dname, loc) VALUES(t2.deptno, t2.dname, t2.loc);
SELECT * FROM tar_dept1;
n 總結
1. MERGE 通常用於數據同步的場景,將一個數據源中的數據同步到另一個數據源(表)中,同時執行更新或插入操作;
2. 注意,在 MERGE 語句中只有當源表中存在查詢出記錄時,才會執行更新或刪除操作。可以這樣理解,如果不分析執行計划,根據推理 MERGE 的執行順序應該是:
1) 首先,查詢源表中的數據;
2) 再根據源表中的每行記錄,去匹配目標表中進行匹配;
3) 匹配到記錄,則執行 THEN UPDATE(更新),否則執行 THEN INSERT(插入);
4) 所以,在源表中不能出現相同的記錄,去多次更新目標表中的同一條記錄。
5. 回滾(rollback)的使用
當我們在編寫 SQL 代碼進行 CUD 時,可以設置回滾點,將當前操作數據回滾到某一個狀態下。創建回滾點使用 SAVEPOINT savepoint_name 語句,回滾到指定位置使用 ROLLBACK TO savepoint_name 語句,示例如下:
--創建表
CREATE TABLE Tab06(id number(3), money number(8,2));
--創建回滾點:SAVE_INSERT
SAVEPOINT SAVE_INSERT;
--插入數據
--TRUNCATE TABLE Tab06;
INSERT ALL
INTO Tab06 VALUES(1, 100)
INTO Tab06 VALUES(2, 200)
SELECT * FROM DUAL;
--創建回滾點:SAVE_UPDATE
SAVEPOINT SAVE_UPDATE;
--更新數據
UPDATE Tab06 SET money = money * 10;
--創建回滾點:SAVE_DELETE
SAVEPOINT SAVE_DELETE;
--刪除數據
DELETE FROM Tab06 WHERE id=2;
--可以混滾到任意個回滾點(但只能依次往前回滾):
ROLLBACK TO SAVE_INSERT;
SELECT * FROM Tab06;
ROLLBACK TO SAVE_UPDATE;
SELECT * FROM Tab06;
ROLLBACK TO SAVE_DELETE;
SELECT * FROM Tab06;
n 注意:
當在設置回滾點之后,執行了 TRUNCATE 語句,回滾點將失效;
當在執行過程中,創建了多個回滾點后,如果回滾到前一個回滾點后,就不能再回滾到后一個回滾點了,只能依次往前回滾。
6. 注意事項
1) 在 Oracle 中,所有有關對數據更改的操作(即:INSERT、UPDATE、DELETE)語句,執行完成后,都必須執行提交命令(COMMIT)。
2) 當使用 FRO UPDATE 語句增刪改時,並點擊鎖表按鈕后會進行鎖表,鎖表后其他會話將不能進行增刪改操作,所以不建議使用該方式。