【问题标题】:Looping and testing the result of a cte in a PostgreSQL trigger在 PostgreSQL 触发器中循环和测试 cte 的结果
【发布时间】:2023-03-18 09:17:01
【问题描述】:

PostgreSQL 11.1

我正在使用以下触发器从 chart_gap 表中获取“新”图表编号:

CREATE FUNCTION phoenix.next_chart()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF 
AS $BODY$
BEGIN
  -- Check for empty chart number
  IF NEW.chart_number is null or NEW.chart_number = 0 THEN
    WITH ins AS (
      SELECT chart_number
      FROM   chart_gap
      WHERE  pg_try_advisory_xact_lock(chart_number)
      LIMIT  1
    )
    DELETE FROM chart_gap c
    USING  ins i
    WHERE  i.chart_number = c.chart_number
    RETURNING i.chart_number INTO NEW.chart_number;
  END IF;

  RETURN NEW;
END;
$BODY$;

我将如何添加测试以确保返回的chart_number 不存在(在表患者中),如果存在,则强制循环以获取表中的下一个图表编号,等等...,直到找到未使用的chart_number?也就是说,触发器必须返回新的和未使用的chart_numbers。

TIA

注意:我最初的想法是使用递归 cte,但认为直接循环可能更快?

【问题讨论】:

    标签: postgresql triggers recursive-cte


    【解决方案1】:

    我希望您有充分的理由不使用序列值。

    您可以简单地用LOOP / END LOOP; 包围代码块,并在末尾添加SELECT count(*) 以测试是否有任何行带有chart_number。只要每笔交易都走这条路线,那应该不会受到竞争条件的影响。

    您必须确保INSERT 发生在同一个事务中,同时持有咨询锁。

    作为咨询锁定的替代方案,您还可以

    SELECT chart_number
    FROM chart_gap
    FOR UPDATE SKIP LOCKED
    LIMIT 1;
    

    这可能更简单。

    【讨论】:

    • 非常感谢。不使用序列的最初原因是几年前(首次编写此触发器时),我想避免使用某些图表编号。然而,由于最初的原因早已被纠正,现在一个序列会很好——但由于图表编号最初是随机分配的,我仍然可能会产生一个已经使用过的图表编号的问题。跨度>
    • 将序列设置为高于表中的值,则不会发生冲突。
    • 您会这样认为(希望),但是在整个地图上都输入了值,留下了 100 个跳过的可用整数。 :)(除此之外,我刚刚发布了另一个相关问题——我似乎无法为 count(*) 使用正确的语法。:(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-13
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 2016-08-22
    • 1970-01-01
    相关资源
    最近更新 更多