本篇介紹如何對錶中的數據進行修改操作,包括插入數據的INSERT
語句、更新數據的UPDATE
語句、刪除數據的DELETE
語句,以及合併數據的INSERT ON CONFLICT
語句。
我們首先創建創建兩個示例表:
CREATE TABLE dept (
department_id int NOT NULL,
department_name varchar(30) NOT NULL,
CONSTRAINT dept_pkey PRIMARY KEY (department_id)
);
CREATE TABLE emp (
employee_id int NOT NULL,
first_name varchar(20) NULL,
last_name varchar(25) NOT NULL,
hire_date date not null default current_date,
salary numeric(8,2) NULL,
manager_id int NULL,
department_id int NULL,
CONSTRAINT emp_pkey PRIMARY KEY (employee_id),
CONSTRAINT fk_emp_dept FOREIGN KEY (department_id) REFERENCES dept(department_id) ON DELETE CASCADE,
CONSTRAINT fk_emp_manager FOREIGN KEY (manager_id) REFERENCES emp(employee_id)
);
關於創建表的CREATE TABLE
語句,可以參考第 06 篇 管理數據表。
插入數據
PostgreSQL 提供了INSERT
語句,可以用於插入一行或者多行數據。
插入單行數據
INSERT
語句的簡單形式如下:
INSERT INTO table_name(column1, column2, ...)
VALUES (value1, value2, ...);
其中,value1 是 column1 的值,value2 是 column2 的值。例如:
INSERT INTO dept(department_id, department_name) VALUES ( 10, 'Administration');
select * from dept;
department_id|department_name|
-------------|---------------|
10|Administration |
如果VALUES
列表爲所有字段都指定了值,並且按照表的字段順序出現,可以省略表名後的字段列表。因此,我們也可以使用以下插入語句:
INSERT INTO dept VALUES ( 20, 'Marketing');
select * from dept;
department_id|department_name|
-------------|---------------|
10|Administration |
20|Marketing |
指定字段的值也可以使用 DEFAULT,表示使用定義字段時的默認值;如果沒有指定默認值使用 NULL 值。
插入多行數據
PostgreSQL 中的INSERT
語句支持一次插入多行數據,在VALUES
之後使用逗號進行分隔。例如:
INSERT INTO emp
VALUES (200, 'Jennifer', 'Whalen', '2020-01-01', 4400.00, NULL, 10),
(201, 'Michael', 'Hartstein', '2020-02-02', 13000.00, NULL, 20),
(202, 'Pat', 'Fay', default, 6000.00, 201, 20);
select * from emp;
employee_id|first_name|last_name|hire_date |salary |manager_id|department_id|
-----------|----------|---------|----------|--------|----------|-------------|
200|Jennifer |Whalen |2020-01-01| 4400.00| | 10|
201|Michael |Hartstein|2020-02-02|13000.00| | 20|
202|Pat |Fay |2020-04-14| 6000.00| 201| 20|
以上語句一次增加了 3 名員工信息,日期可以使用字符形式的字面值(‘2020-01-01’),default 表示使用默認的當前日期。
複製數據
INSERT INTO SELECT
語句可以將一個查詢語句的結果插入表中。例如:
create table emp1 (like emp);
insert into emp1
select * from emp
where department_id = 20;
select * from emp1;
employee_id|first_name|last_name|hire_date |salary |manager_id|department_id|
-----------|----------|---------|----------|--------|----------|-------------|
201|Michael |Hartstein|2020-02-02|13000.00| | 20|
202|Pat |Fay |2020-04-14| 6000.00| 201| 20|
我們首先基於 emp 創建了一個新表 emp1,然後通過查詢語句將 emp 中的部分數據複製到 emp1 中。
返回插入的數據
PostgreSQL 對 SQL進行了擴展,可以在INSERT
語句之後使用RETURNING
返回插入的數據值。例如:
insert into dept
values (30, 'Purchasing')
returning department_id;
department_id|
-------------|
30|
以上語句除了插入一條數據到 dept 表中,同時還返回了該數據的 department_id。
更新數據
單表更新
PostgreSQL 使用UPDATE
語句更新表中已有的數據,基本的語法如下:
UPDATE table_name
SET column1 = value1,
column2 = value2,
...
WHERE conditions;
其中,WHERE
決定了需要更新的數據行,只有滿足條件的數據纔會更新;如果省略WHERE
條件,將會更新表中的所有數據,需要謹慎使用。
以下語句將編號爲 200 的員工從原部門調動到 Marketing,並且漲薪 1000:
update emp
set salary = salary + 1000,
department_id = 20
where employee_id = 200;
跨表更新
除了以上形式的更新語句之外,PostgreSQL 還支持通過關聯其他表中的數據進行更新。以下語句利用 emp 中的數據更新 emp1 表:
update emp1
set salary = emp.salary,
department_id = emp.department_id,
manager_id = emp.manager_id
from emp
where emp1.employee_id = emp.employee_id;
我們使用FROM
子句訪問 emp 中的數據,並且在WHERE
子句中指定了兩個表的關聯條件。這種語句與多表連接查詢(join)類似,有時候也稱爲多表連接更新(UPDATE JOIN)。
返回更新後的數據
PostgreSQL 同樣對UPDATE
語句進行了擴展,支持使用RETURNING
返回更新後的數據值。例如:
update emp
set salary = salary + 1000,
department_id = 20
where employee_id = 200
returning first_name, last_name, salary;
first_name|last_name|salary |
----------|---------|-------|
Jennifer |Whalen |6400.00|
我們再次更新編號爲 200 的員工的信息,並且返回了更新之後的記錄。
刪除數據
刪除數據可以使用DELETE
語句:
DELETE FROM table_name
WHERE conditions;
同樣,只有滿足WHERE
條件的數據纔會被刪除;如果省略,將會刪除表中所有的數據。
單表刪除
以下語句用於刪除 emp1 中員工編號爲 201 的數據:
delete
from emp1
where employee_id = 201;
如果沒有編號爲 201 的數據,不會刪除任何數據。
跨表刪除
PostgreSQL 同樣支持通過關聯其他表進行數據刪除。以下語句利用 emp 表刪除 emp1 表中的數據:
delete
from emp1
using emp
where emp1.employee_id = emp.employee_id;
注意,跨表刪除使用USING
關鍵字引用其他的表,而不是JOIN
。以上語句了 emp1 中員工編號存在於 emp 表中的數據,等價於以下子查詢實現:
delete
from emp1
where emp1.employee_id in (select employee_id from emp);
返回被刪除的數據
PostgreSQL 中的DELETE
語句也可以使用RETURNING
返回被刪除的數據。例如:
-- 先插入一些數據
insert into emp1
select * from emp
where department_id = 20;
delete
from emp1
returning *;
employee_id|first_name|last_name|hire_date |salary |manager_id|department_id|
-----------|----------|---------|----------|--------|----------|-------------|
201|Michael |Hartstein|2020-02-02|13000.00| | 20|
202|Pat |Fay |2020-04-14| 6000.00| 201| 20|
200|Jennifer |Whalen |2020-01-01| 6400.00| | 20|
我們先從 emp 複製了一些數據到 emp1 中,然後刪除所有數據並且返回這些記錄。
合併數據
在 SQL 標準中還定義了一個合併數據的語句:MERGE
。PostgreSQL 沒有實現該語句,但是可以通過INSERT INTO ON CONFLICT
實現數據合併的功能。
INSERT INTO table_name(column1, column2, ...)
{VALUES (value1, value2, ...) | SELECT ...}
ON CONFLICT conflict_target conflict_action;
其中,conflict_target 是判斷數據是否已經存在的條件:
- ( { index_column_name | ( index_expression ) } ) ,基於某個具有索引的字段或者表達式進行判斷;
- ON CONSTRAINT constraint_name,基於某個唯一約束進行判斷。
conflict_action 表示衝突時採取的操作:
- DO NOTHING,如果數據已經存在,不做任何操作;
- DO UPDATE SET,如果數據已經存在,更新該數據;可以使用
WHERE
子句進一步限制需要更新的數據。
這種語句通過爲INSERT
語句增加ON CONFLICT
選項,組合了INSERT
和UPDATE
語句的功能,因此也被稱爲UPSERT
語句。
衝突時不做任何操作
emp 表中已經存在編號爲 200 的員工,如果我們再次插入該編號將會提示主鍵衝突:
insert into emp
values (200, 'Jennifer', 'Whalen', '2020-01-01', 4400.00, NULL, 10)
SQL Error [23505]: ERROR: duplicate key value violates unique constraint "emp_pkey"
Detail: Key (employee_id)=(200) already exists.
此時,我們可以增加衝突處理,從而避免語句出錯:
insert into emp
values (200, 'Jennifer', 'Whalen', '2020-01-01', 4400.00, NULL, 10)
on conflict (employee_id)
do nothing;
以上語句基於 employee_id 字段是否重複進行判斷,衝突時不做任何處理。
衝突時更新目標數據
另一種處理衝突的方式就是進行數據更新:
select department_id
from emp
where employee_id = 200;
department_id|
-------------|
20|
insert into emp
values (200, 'Jennifer', 'Whalen', '2020-01-01', 4400.00, NULL, 10)
on conflict on constraint emp_pkey
do update
set first_name = EXCLUDED.first_name,
last_name = EXCLUDED.last_name,
hire_date = EXCLUDED.hire_date,
salary = EXCLUDED.salary,
manager_id =EXCLUDED.manager_id,
department_id = EXCLUDED.department_id;
select *
from emp
where employee_id = 200;
employee_id|first_name|last_name|hire_date |salary |manager_id|department_id|
-----------|----------|---------|----------|-------|----------|-------------|
200|Jennifer |Whalen |2020-01-01|4400.00| | 10|
該員工的部門編號在前面被修改爲 20;我們通過主鍵約束 emp_pkey 進行重複數據的判斷,然後更新該員工的數據;EXCLUDED 是一個特殊的表,代表了原本應該插入的數據行;最終該員工的部門編號被更新爲 10。
歡迎點贊👍、評論📝、收藏❤️!