在 PostgreSQL 触发器中循环和测试 cte 的结果

Looping and testing the result of a cte in a PostgreSQL trigger

PostgreSQL 11.1

我正在使用以下触发器从 chart_gap table 中获取 "new" 图表编号:

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$;

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

TIA

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

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

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

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

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

SELECT chart_number
FROM chart_gap
FOR UPDATE SKIP LOCKED
LIMIT 1;

哪个可能更简单。