【问题标题】:PostgreSQL declaring and use serial variables inside trigger functionPostgreSQL 在触发函数中声明和使用串行变量
【发布时间】:2015-02-16 10:09:19
【问题描述】:
CREATE OR REPLACE FUNCTION function_create_forum()
  RETURNS trigger AS
  $$
  BEGIN
    DECLARE  id_course   serial; 

    select id INTO id_course   FROM INSERTED;

    insert INTO Forum (course,name,type,staff_only) VALUES 
                      (id_course,"Staff lounge",1,true);
    --forum 2 creation
    --forum 3 creation

  END;
  $$
  LANGUAGE plpgsql VOLATILE;

触发器功能应该创建一个新论坛,只要创建了一个课程,该课程有一个“id”字段是串行的,这会导致问题,因为在“DECLARE”区域内不被接受。

由于在 cmets 中任何人继续指出上面的语法是不正确的(不管在所有其他不使用“串行”的触发器中都可以正常工作),这是代码的另一种变体不起作用。

CREATE OR REPLACE FUNCTION function_create_forum()
  RETURNS trigger AS
  $$
  DECLARE
    id_course int;
  BEGIN

    select id INTO id_course   FROM INSERTED; 

    insert INTO Forum (course,name,type,staff_only) VALUES 
                      (id_course,"Staff lounge",1,true);
    --forum 2 creation
    --forum 3 creation

  END;
  $$
  LANGUAGE plpgsql VOLATILE;

表创建:

CREATE TABLE Forum (
    course serial REFERENCES Course(id) ON DELETE CASCADE NOT NULL,
    --omitted details
);

CREATE TABLE Course (
    id   serial  UNIQUE NOT NULL, --the primary key is another column
    --omitted details
)

【问题讨论】:

  • serial 不是一个独特的数据类型,它只是声明 int 类型的简写,默认子句具有序列的nextval()(但仅在表上下文中)postgresql.org/docs/current/static/… - - 在其他情况下,只需使用 int。
  • int 不起作用(试过)DECLARE id_course int;
  • 为什么?错误信息?更多细节?这也行不通,但毕竟这行不通。 -- 我现在明白了,您的语法无效:您只能有一个 DECLARE 块,before BEGIN 块 postgresql.org/docs/current/static/plpgsql-declarations.html
  • 仍然,你不能使用 serial (这不是真正的类型),使用 int -- 声明不能在 begin-end 块内,除非它有一个单独的内部 begin-end 块也(请参阅我提供的链接中的示例)
  • 不管在所有其他触发器中都可以正常工作” - 我非常怀疑这一点。 Postgres 中没有inserted

标签: sql postgresql triggers


【解决方案1】:

正如其他人已经评论的那样,没有“数据类型”序列。

Quote from the manual

smallserial、serial 和 bigserial 数据类型不是真正的类型,而只是 一种符号方便,用于创建唯一标识符列(类似于某些其他数据库支持的 AUTO_INCREMENT 属性)

强调我的

我可以看到的一个基本问题是这一行:

select id INTO id_course   FROM INSERTED; 

Postgres 中没有“插入”虚拟表(例如在 SQL Server 中)如果您创建行级触发器,那么您可以使用 NEW 变量 which is implicitly defined in a trigger function 访问新行的值。

另一个问题是"Staff lounge"。双引号用于表示列(或表)名称,而不是字符文字。 Character literals are enclosed in single quotes in SQL.

所以你的触发函数应该是这样的:

CREATE OR REPLACE FUNCTION function_create_forum()
  RETURNS trigger AS
  $$
  BEGIN

    insert INTO Forum (course,name,type,staff_only) VALUES 
                      (new.id,'Staff lounge',1,true);
    --forum 2 creation
    --forum 3 creation

  END;
  $$
  LANGUAGE plpgsql VOLATILE;

您没有向我们展示您的 create trigger 语句,但它应该是这样的,以确保您正在创建行级触发器:

CREATE TRIGGER course_insert_trg 
   AFTER INSERT ON course  --<< AFTER is important!
   FOR EACH ROW ---<<< this makes it a row level trigger
   EXECUTE PROCEDURE function_create_forum();

【讨论】:

  • 这不起作用,因为“new.id”指的是不存在的行(因此违反了论坛的参考)
  • @DarioOO:啊,对。您需要将其更改为 after insert 触发器。
猜你喜欢
  • 1970-01-01
  • 2013-07-20
  • 2019-04-25
  • 2017-03-09
  • 2019-03-26
  • 2016-07-12
  • 2017-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多