通过从单个 table 中选择来插入两个引用 table
Insert into two referencing tables by selecting from a single table
我的 PostgreSQL 12 数据库中有 2 个永久性 table,它们具有一对多关系(thing
和 thing_identifier
)。第二个 -- thing_identifier
-- 有一个引用 thing
的列,这样 thing_identifier
可以为给定的 thing
:
保存多个外部标识符
CREATE TABLE IF NOT EXISTS thing
(
thing_id SERIAL PRIMARY KEY,
thing_name TEXT, --this is not necessarily unique
thing_attribute TEXT --also not unique
);
CREATE TABLE IF NOT EXISTS thing_identifier
(
id SERIAL PRIMARY KEY,
thing_id integer references thing (thing_id),
identifier text
);
我需要向 thing
和 thing_identifier
中插入一些新数据,这两个数据都来自我通过使用 COPY
提取内容创建的 table一个大的 CSV 文件到数据库中,类似于:
CREATE TABLE IF NOT EXISTS things_to_add
(
id SERIAL PRIMARY KEY,
guid TEXT, --a unique identifier used by the supplier
thing_name TEXT, --not unique
thing_attribute TEXT --also not unique
);
示例数据:
INSERT INTO things_to_add (guid, thing_name) VALUES
('[111-22-ABC]','Thing-a-ma-jig','pretty thing'),
('[999-88-XYZ]','Herk-a-ma-fob','blue thing');
目标是让 things_to_add
中的每一行在 thing
和 thing_identifier
中产生一个新行,如下所示:
thing
:
| thing_id | thing_name | thing attribute |
|----------|---------------------|-------------------|
| 1 | thing-a-ma-jig | pretty thing
| 2 | herk-a-ma-fob | blue thing
thing_identifier
:
| id | thing_id | identifier |
|----|----------|------------------|
| 8 | 1 | '[111-22-ABC]' |
| 9 | 2 | '[999-88-XYZ]' |
我可以使用 CTE INSERT
语句(使用 RETURNING thing_id
)来获取 thing_id
由 thing
上的 INSERT
产生的 thing_id
,但是我无法弄清楚如何从 thing
和 上的 INSERT
获得 both that thing_id
来自 things_to_add
的原始 guid
,需要进入 thing_identifier.identifier
.
明确一点,thing
中唯一保证唯一的列是 thing_id
,things_to_add
中唯一保证唯一的列是 id
(我们不不想存储)和guid
(这是我们想要的thing_identifier.identifier
),所以没有办法在[=之后加入thing
和things_to_add
30=] 在 thing
.
您可以从 JOIN
检索 thing_to_add.guid :
WITH list AS
(
INSERT INTO thing (thing_name)
SELECT thing_name
FROM things_to_add
RETURNING thing_id, thing_name
)
INSERT INTO thing_identifier (thing_id, identifier)
SELECT l.thing_id, t.guid
FROM list AS l
INNER JOIN thing_to_add AS t
ON l.thing_name = t.thing_name
那么,如果thing.thing_name
不是唯一的,问题就比较棘手了。从 thing_to_add
上的同一个触发器更新两个表 thing
和 thing_identifier
可能会解决问题:
CREATE OR REPLACE FUNCTION after_insert_thing_to_add ()
RETURNS TRIGGER LANGUAGE sql AS
$$
WITH list AS
(
INSERT INTO thing (thing_name)
SELECT NEW.thing_name
RETURNING thing_id
)
INSERT INTO thing_identifier (thing_id, identifier)
SELECT l.thing_id, NEW.guid
FROM list AS l ;
$$
DROP TRIGGER IF EXISTS after_insert ON thing_to_add ;
CREATE TRIGGER after_insert
AFTER INSERT
ON thing_to_add
FOR EACH ROW
EXECUTE PROCEDURE after_insert_thing_to_add ();
我的 PostgreSQL 12 数据库中有 2 个永久性 table,它们具有一对多关系(thing
和 thing_identifier
)。第二个 -- thing_identifier
-- 有一个引用 thing
的列,这样 thing_identifier
可以为给定的 thing
:
CREATE TABLE IF NOT EXISTS thing
(
thing_id SERIAL PRIMARY KEY,
thing_name TEXT, --this is not necessarily unique
thing_attribute TEXT --also not unique
);
CREATE TABLE IF NOT EXISTS thing_identifier
(
id SERIAL PRIMARY KEY,
thing_id integer references thing (thing_id),
identifier text
);
我需要向 thing
和 thing_identifier
中插入一些新数据,这两个数据都来自我通过使用 COPY
提取内容创建的 table一个大的 CSV 文件到数据库中,类似于:
CREATE TABLE IF NOT EXISTS things_to_add
(
id SERIAL PRIMARY KEY,
guid TEXT, --a unique identifier used by the supplier
thing_name TEXT, --not unique
thing_attribute TEXT --also not unique
);
示例数据:
INSERT INTO things_to_add (guid, thing_name) VALUES
('[111-22-ABC]','Thing-a-ma-jig','pretty thing'),
('[999-88-XYZ]','Herk-a-ma-fob','blue thing');
目标是让 things_to_add
中的每一行在 thing
和 thing_identifier
中产生一个新行,如下所示:
thing
:
| thing_id | thing_name | thing attribute |
|----------|---------------------|-------------------|
| 1 | thing-a-ma-jig | pretty thing
| 2 | herk-a-ma-fob | blue thing
thing_identifier
:
| id | thing_id | identifier |
|----|----------|------------------|
| 8 | 1 | '[111-22-ABC]' |
| 9 | 2 | '[999-88-XYZ]' |
我可以使用 CTE INSERT
语句(使用 RETURNING thing_id
)来获取 thing_id
由 thing
上的 INSERT
产生的 thing_id
,但是我无法弄清楚如何从 thing
和 上的 INSERT
获得 both that thing_id
来自 things_to_add
的原始 guid
,需要进入 thing_identifier.identifier
.
明确一点,thing
中唯一保证唯一的列是 thing_id
,things_to_add
中唯一保证唯一的列是 id
(我们不不想存储)和guid
(这是我们想要的thing_identifier.identifier
),所以没有办法在[=之后加入thing
和things_to_add
30=] 在 thing
.
您可以从 JOIN
检索 thing_to_add.guid :
WITH list AS
(
INSERT INTO thing (thing_name)
SELECT thing_name
FROM things_to_add
RETURNING thing_id, thing_name
)
INSERT INTO thing_identifier (thing_id, identifier)
SELECT l.thing_id, t.guid
FROM list AS l
INNER JOIN thing_to_add AS t
ON l.thing_name = t.thing_name
那么,如果thing.thing_name
不是唯一的,问题就比较棘手了。从 thing_to_add
上的同一个触发器更新两个表 thing
和 thing_identifier
可能会解决问题:
CREATE OR REPLACE FUNCTION after_insert_thing_to_add ()
RETURNS TRIGGER LANGUAGE sql AS
$$
WITH list AS
(
INSERT INTO thing (thing_name)
SELECT NEW.thing_name
RETURNING thing_id
)
INSERT INTO thing_identifier (thing_id, identifier)
SELECT l.thing_id, NEW.guid
FROM list AS l ;
$$
DROP TRIGGER IF EXISTS after_insert ON thing_to_add ;
CREATE TRIGGER after_insert
AFTER INSERT
ON thing_to_add
FOR EACH ROW
EXECUTE PROCEDURE after_insert_thing_to_add ();