gpt4 book ai didi

sql - 插入和返回新记录或现有记录的 ID,在 Postgres 12.5 中需要更好的策略

转载 作者:行者123 更新时间:2023-12-05 06:57:17 24 4
gpt4 key购买 nike

我正在尝试在 Postgres 12.5 中做一些事情,但我要么遗漏了一个细节,要么完全追求一个有缺陷的策略。我有一个简单的查找表,其中包含一些较长的字符串和扩展的详细信息。当数据流入主表时,我想将这些字符串转换为一个简单的 int 作为键。我想我可以将查找保存在一个表中,然后使用 INSERT....ON CONFLICT DO NOTHING...RETURNING 来获得这些结果:

  • 如果查找表中不存在该行,则创建它并返回新的id。 <-- 这行得通。
  • 如果该行确实存在,则不要覆盖它并返回新的 id。 <-- 未返回 id

第二种情况更为常见。很有可能,系统会在新值到达查找表之间运行数天或数周。我更喜欢果断地执行 INSERT 以避免并发问题或唯一冲突。然而,RETURNING 并没有像我希望的那样工作。我检查了文档,清楚地记录了我所看到的行为。而且,考虑一下,很有意义。因此,继续前进,编写一个函数来测试结果并发出 SELECT id FROM pgconfig_target WHERE... 以恢复现有的 id 是否更有意义,还是其他一些更直接的策略?

作为背景,主表是一个 push_audit_log 总结了来 self 们客户的 insert 调用,包括时间、记录计数和其他详细信息。这些记录将会很多。这就是为什么我宁愿将字符串转移到另一个表。

这是查找表设置的简短版本:

--------------------------------------
-- Define table
------------------------------------
BEGIN;

DROP TABLE IF EXISTS dba.pgconfig_target CASCADE;

CREATE TABLE IF NOT EXISTS dba.pgconfig_target (
id int2 GENERATED ALWAYS AS IDENTITY,
schema_name citext NOT NULL DEFAULT NULL,
target_name citext NOT NULL DEFAULT NULL,
target_path citext NOT NULL DEFAULT NULL
);

ALTER TABLE dba.pgconfig_target
OWNER TO user_change_structure;

COMMIT;

------------------------------------
-- Build indexes
------------------------------------
CREATE UNIQUE INDEX pgconfig_target_unique_ix_btree
ON dba.pgconfig_target (schema_name, target_name, target_path);

这是我正在试验的 INSERT:

INSERT INTO pgconfig_target (schema_name, target_name, target_path) 
VALUES ('hello','world','passthrough.hello.world')
ON CONFLICT (schema_name,target_name,target_path) do nothing
RETURNING id;

感谢您的建议。

#稍后#我想使用像列出的(曾经有用的)GMB 这样的建议,但似乎无法让它在第一次运行时工作。我很好奇为什么,因为我不理解有关命令或执行的某些内容。

我尝试了一些 scratch 函数,它确实有效,但如果可能的话,纯 SQL 语句解决方案似乎更好一些。这是函数:

CREATE OR REPLACE FUNCTION ascendco.pgconfig_target_add_if_missing (
s_name citext,
t_name citext,
t_path citext
)

RETURNS integer AS

$BODY$

DECLARE
id_out integer = 0;

BEGIN

-- Insert the value, if it's missing.
INSERT INTO pgconfig_target (schema_name, target_name, target_path)
VALUES (s_name, t_name, t_path)
ON CONFLICT DO NOTHING;

-- The ID should be there, either historically or becase it was just added.
SELECT id
FROM pgconfig_target
WHERE schema_name = s_name
AND target_name = t_name
AND target_path = t_path
INTO id_out;

return id_out;

END

$BODY$
LANGUAGE plpgsql;

这样的示例调用:

   select * from pgconfig_target_add_if_missing ('hello', 'world', 'checking.it.out')

我正在使用 select *,因为我没有理清使 id 成为明确结果的语法。

最佳答案

这就是 on conflict 的工作原理。如果没有插入行,则不返回任何内容。

解决方法是使用 CTE 重新表述逻辑:首先插入(或什么都不做),然后再次从表中选择,使用输入数据进行过滤。

with 
data as (
select *
from (values
('hello','world','passthrough.hello.world')
) v(schema_name, target_name, target_path)
),
ins as (
insert into pgconfig_target (schema_name, target_name, target_path)
select *
from data
on conflict (schema_name, target_name, target_path) do nothing
)
select c.id
from pgconfig_target c
inner join data d using (schema_name, target_name, target_path)

关于sql - 插入和返回新记录或现有记录的 ID,在 Postgres 12.5 中需要更好的策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64920254/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com