【问题标题】:Problems with creating a postgresql trigger function to create a modified entry for every insert statement创建 postgresql 触发器函数以为每个插入语句创建修改条目的问题
【发布时间】:2021-03-17 18:24:25
【问题描述】:

所以我在这里的第一个问题是, 让我描述一下设置: 我有一个带有表 guilds 的 postgressql 数据库(版本 12)(包含内部 guild_id 和一些其他信息)。 guild_id 用作许多其他表(如团队表)的外键。现在,如果一个团队被插入到另一个公会的团队中,那么 guild_id = 1 的公会,我想要一个触发器函数来创建相同的团队条目,但现在使用修改后的 guild_id(现在应该是 1)。

我有atm的相关东西的定义:

create table if not exists bot.guilds
(
    guild_id         bigserial not null
        constraint guilds_pk
            primary key,
    guild_dc_id      bigint    not null,
);
create table if not exists bot.teams
(
    team_id       bigserial   not null
        constraint teams_pk
            primary key,
    guild_id      bigserial      not null
        constraint teams_guilds_guild_id_fk
            references bot.guilds
            on delete cascade,
    team_name     varchar(20) not null,
    team_nickname varchar(10) not null
);

alter table bot.teams
    owner to postgres;

create unique index if not exists teams_guild_id_team_name_uindex
    on bot.teams (guild_id, team_name);

create unique index if not exists teams_guild_id_team_nickname_uindex
    on bot.teams (guild_id, team_nickname);

create function duplicate_teams() returns trigger
    language plpgsql
as
$$
BEGIN
    INSERT INTO bot.teams VALUES(1,NEW."team_name",NEW."team_nickname");
RETURN NEW;
END;
$$;

create trigger duplicate_team
    after insert
    on bot.teams
    for each row
execute procedure bot.duplicate_teams();

如果我现在尝试在团队中插入新行 (INSERT INTO bot.teams ("guild_id", "team_name", "team_nickname")VALUES (14, 'test2', 'test2');),我会收到以下错误消息(原始德语,由我翻译成英语):

[42804] ERROR: Column »guild_id« has type integer, but the expression has the type character varying
HINT: You have to rewrite the expression or cast the value.
WITH: PL/pgSQL-function duplicate_teams() row 3 in SQL-expressions

执行后原始插入语句不在表中,副本也不在表中。 我试图将公会 ID 的值转换为序列、整数、大序列..但每次都出现相同的错误。我对错误消息部分与“类型字符不同”感到困惑。

所以我的问题是:

  1. 我的理解是否正确,错误是由触发器引起的?并且由于触发器中的错误,原始插入语句也不起作用?
  2. 为什么即使使用强制转换,类型也会变化?
  3. 代码错误在哪里?

我试图搜索问题,但没有发现任何有用的信息。欢迎任何提示。感谢您的帮助!

编辑: @Lukas Thaler 的答案有效,但现在我得到一个新错误:

[23505] ERROR: doubled key value violates unique-constraint »teams_guild_id_team_name_uindex«
Detail: Key»(guild_id, team_name)=(1, test3)« exists already.
WHERE: SQL-Statement»INSERT INTO bot.teams(guild_id, team_name, team_nickname)  VALUES(1,NEW."team_name",NEW."team_nickname")«
PL/pgSQL-Function duplicate_teams() row 3 in SQL-Statement
SQL-Statment »INSERT INTO bot.teams(guild_id, team_name, team_nickname)  VALUES(1,NEW."team_name",NEW."team_nickname")«
PL/pgSQL-Function duplicate_teams() row 3 in SQL-Statement

但该表只包含“3,11,TeamUtils,TU”...

【问题讨论】:

  • 注意:a) 序列号在Don't Do this,b) 你想INSERT INTO bot.teams AFTER INSERT ON bot.teams吗?
  • 参考您的编辑:您可以尝试做select currval('bot.teams_guild_id_seq')吗?正如@AlexYu 提到的,SERIALS 有时会很奇怪。鉴于这是一个外键,无论如何,您最好将 bot.teams.guild_id 转换为 BIGINT(我不认为自动递增是子表中的预期行为)

标签: postgresql


【解决方案1】:

bot.teams 有四列:team_idguild_id(均为数字数据类型)、team_nameteam_nickname(均为 varchars)。在函数定义中的INSERT 语句中,您只提供了三个值并且没有与特定列的关联。默认是按顺序插入它们,将1 分配给team_id 和(至关重要)将NEW."team_name" 分配给guild_id,因此插入失败并出现类型不匹配错误。

指定

INSERT INTO bot.teams(guild_id, team_name, team_nickname)  VALUES(1,NEW."team_name",NEW."team_nickname");

在你的函数中应该可以解决你的问题


回答您的其他问题:

  1. INSERT 语句正在transaction 内部执行,触发器中的失败将导致整个事务中止并回滚,因此您也看不到插入到表中的原始行
  2. 类型没有偏离强制转换,是插入的错误值导致数据类型不匹配

【讨论】:

  • 哦,该死的,我很愚蠢。现在出现另一个错误:)。感谢您迄今为止的帮助!
  • 您能解释一下为什么将 1 传递给 guild_id 吗?这对我来说看起来很奇怪。这是某种serial 的行为吗?
  • 1(与所有其他插入的值一样)取自他们帖子中的 OP 函数定义。我不知道他们的意图是什么,那里
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-07
  • 1970-01-01
  • 1970-01-01
  • 2021-08-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多