仅当记录存在时才插入 Postgres table
Insert into Postgres table only if record exists
我正在用 Postgres 编写一些 sql 来更新审计 table。我的 sql 将根据某些标准更新正在审核的 table,然后 select 更新记录以更新审核 table 中的信息。这是我目前所拥有的:
DO $$
DECLARE
jsonValue json;
revId int;
template RECORD;
BEGIN
jsonValue = '...Some JSON...'
UPDATE projectTemplate set json = jsonValue where type='InstallationProject' AND account_id IS NULL;
template := (SELECT pt FROM ProjectTemplate pt WHERE pt.type='InstallationProject' AND pt.account_id IS NULL);
IF EXISTS (template) THEN
(
revId := nextval('hibernate_sequence');
insert into revisionentity (id, timestamp) values(revId, extract(epoch from CURRENT_TIMESTAMP));
insert into projectTemplate_aud (rev, revtype, id, name, type, category, validfrom, json, account_id)
VALUES (revId, 1, template.id, template.name, template.type, template.category, template.validfrom, jsonValue, template.account_id);
)
END $$;
我的理解是,如果 table 中没有与该查询匹配的内容(目前没有),则 template
将是未定义的。我想这样做,如果 template
不存在,我的查询将不会尝试更新审计 table。
我该怎么做才能更新此 sql 以匹配我正在尝试做的事情?
你不能那样使用 EXISTS
,它需要一个 subquery 表达式。加上您的代码的其他一些问题。
这个带有 data-modifying CTE 的 SQL DML 语句应该正确地替换你的 DO
命令。而且速度也更快:
WITH upd AS (
UPDATE ProjectTemplate
SET json = '...Some JSON...'
WHERE type = 'InstallationProject'
AND account_id IS NULL
RETURNING *
)
, ins AS (
INSERT INTO revisionentity (id, timestamp)
SELECT nextval('hibernate_sequence'), extract(epoch FROM CURRENT_TIMESTAMP)
WHERE EXISTS (SELECT FROM upd) -- minimal valid EXISTS expression!
RETURNING id
)
INSERT INTO ProjectTemplate_aud
(rev , revtype, id, name, type, category, validfrom, json, account_id)
SELECT i.id, 1 , u.id, u.name, u.type, u.category, u.validfrom, u.json, u.account_id
FROM upd u, ins i;
如果 UPDATE
找到任何行,则在 revisionentity
中插入 单个 行。
插入与已更新的行一样多的行 projectTemplate_aud
。
关于 data-modifying 个 CTE:
- Insert data in 3 tables at a time using Postgres
旁白:我看到 CaMeL-case、一些下划线或只是小写的名称。只考虑合法的 lower-case 名称(并避免将基本类型名称作为列名称)。不过,最重要的是 一致 。相关:
- Are PostgreSQL column names case-sensitive?
我正在用 Postgres 编写一些 sql 来更新审计 table。我的 sql 将根据某些标准更新正在审核的 table,然后 select 更新记录以更新审核 table 中的信息。这是我目前所拥有的:
DO $$
DECLARE
jsonValue json;
revId int;
template RECORD;
BEGIN
jsonValue = '...Some JSON...'
UPDATE projectTemplate set json = jsonValue where type='InstallationProject' AND account_id IS NULL;
template := (SELECT pt FROM ProjectTemplate pt WHERE pt.type='InstallationProject' AND pt.account_id IS NULL);
IF EXISTS (template) THEN
(
revId := nextval('hibernate_sequence');
insert into revisionentity (id, timestamp) values(revId, extract(epoch from CURRENT_TIMESTAMP));
insert into projectTemplate_aud (rev, revtype, id, name, type, category, validfrom, json, account_id)
VALUES (revId, 1, template.id, template.name, template.type, template.category, template.validfrom, jsonValue, template.account_id);
)
END $$;
我的理解是,如果 table 中没有与该查询匹配的内容(目前没有),则 template
将是未定义的。我想这样做,如果 template
不存在,我的查询将不会尝试更新审计 table。
我该怎么做才能更新此 sql 以匹配我正在尝试做的事情?
你不能那样使用 EXISTS
,它需要一个 subquery 表达式。加上您的代码的其他一些问题。
这个带有 data-modifying CTE 的 SQL DML 语句应该正确地替换你的 DO
命令。而且速度也更快:
WITH upd AS (
UPDATE ProjectTemplate
SET json = '...Some JSON...'
WHERE type = 'InstallationProject'
AND account_id IS NULL
RETURNING *
)
, ins AS (
INSERT INTO revisionentity (id, timestamp)
SELECT nextval('hibernate_sequence'), extract(epoch FROM CURRENT_TIMESTAMP)
WHERE EXISTS (SELECT FROM upd) -- minimal valid EXISTS expression!
RETURNING id
)
INSERT INTO ProjectTemplate_aud
(rev , revtype, id, name, type, category, validfrom, json, account_id)
SELECT i.id, 1 , u.id, u.name, u.type, u.category, u.validfrom, u.json, u.account_id
FROM upd u, ins i;
如果 UPDATE
找到任何行,则在 revisionentity
中插入 单个 行。
插入与已更新的行一样多的行 projectTemplate_aud
。
关于 data-modifying 个 CTE:
- Insert data in 3 tables at a time using Postgres
旁白:我看到 CaMeL-case、一些下划线或只是小写的名称。只考虑合法的 lower-case 名称(并避免将基本类型名称作为列名称)。不过,最重要的是 一致 。相关:
- Are PostgreSQL column names case-sensitive?