【问题标题】:Setting a value to the result of a subquery in a function in postgresql在 postgresql 的函数中将值设置为子查询的结果
【发布时间】:2019-05-31 22:16:11
【问题描述】:

我正在尝试为触发器编写一个函数,以检查关系中新条目中的日期是否大于其他关系中的条目。如果是这种情况,我想将新关系中的日期值更新为其他关系中的日期值:

create or replace function curDate()
returns trigger as $$
Begin
    if (new.date >= (select date from other where new.name = other.name )) then
        set new.date = (select date from playlist where new.name = other.name );
    end if;
end; $$ language plpgsql;

我收到语法错误:set new.date = (select date from playlist where new.name = other.name )

但是,这很好用:

create or replace function curDate()
    returns trigger as $$
    declare dateVar date;
Begin
    dateVar := (select date from other where new.name = other.name);
    if (new.datum >= dateVar) then
        new.datum = dateVar;
    end if;
end; $$ language plpgsql;

这是为什么呢?

【问题讨论】:

  • 关键字 set 在 plpgsql 的赋值中只是多余的。顺便说一句,函数应该return new;
  • 我们需要查看触发器才能完全正确地获取触发器功能。并且始终是您的 Postgres 版本。 date 还是 datum?是否所有涉及的列都定义了NOT NULLother.name UNIQUE
  • 那么你有答案了吗?

标签: sql postgresql subquery plpgsql


【解决方案1】:

假设所有涉及的列 NOT NULLother.name UNIQUE 以避免并发症。

使用一个 SELECT查询分配NEW.datum

CREATE OR REPLACE FUNCTION trg_cur_date()
  RETURNS TRIGGER AS
$func$
BEGIN
   SELECT o.datum
   FROM   other o
   WHERE  o.name  = NEW.name
   AND    o.datum < NEW.datum

   UNION ALL SELECT NEW.datum
   LIMIT  1

   INTO   NEW.datum;

   RETURN NEW;  -- required for BEFORE INSERT trigger
END
$func$  LANGUAGE plpgsql;

对于像这样的触发器:

CREATE TRIGGER playlist_ins_bef
BEFORE INSERT ON playlist
FOR EACH ROW EXECUTE PROCEDURE trg_cur_date();

db小提琴here

SELECT INTO (不要与 SQL SELECT INTO 混淆,不鼓励使用它) 可以像= or := 一样进行赋值。没有SET

如果没有符合条件的行,一个普通的SELECT INTO 将分配NULLThe manual:

... target 将设置为查询返回的第一行,如果查询没有返回任何行,则设置为 null。

附加UNION ALL SELECT NEW.datum LIMIT 1 默认为原始值。见:

这样,我们只执行带有 one 赋值的 one 查询。

【讨论】:

    【解决方案2】:

    要将查询结果存储到变量中,请使用select into

    create or replace function curDate()
    returns trigger as $$
    Begin
      if (new.date >= (select date from other where new.name = other.name )) then
        select date 
          into new.date 
        from other 
        where new.name = other.name;
      end if;
    end; $$ language plpgsql;
    

    这可以通过只运行一次 SELECT 来进一步优化。

    create or replace function curDate()
    returns trigger as $$
    declare
       l_date date;
    Begin
      select date 
        into l_date
      from other 
      where new.name = other.name;
    
      if (new.date >= l_date) then
        new.date := l_date;
      end if;
    end; $$ language plpgsql;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-28
      • 1970-01-01
      • 2016-06-10
      • 1970-01-01
      • 2015-01-02
      • 1970-01-01
      • 2019-01-08
      • 1970-01-01
      相关资源
      最近更新 更多