Postgresql 基于其他列在列中插入实数旧插入

Postgresql 基于其他列在列中插入实数旧插入,postgresql,triggers,autofill,Postgresql,Triggers,Autofill,在PostgreSQL中,我有一个表。。。(最左侧的“stmtserial”中有一个主键序列列,此图中未显示) 在上表中,除了通过插入前每行触发器自动填充的“时间索引”之外,所有列都是通过查询输入的 这是创建相同表(没有任何值)的代码,因此每个人都可以使用PostgreSQL查询面板创建它 CREATE TABLE table_ebscb_spa_log04 ( pcnum smallint, stmtserial integer NOT NULL DEFAULT nextva

在PostgreSQL中,我有一个表。。。(最左侧的“stmtserial”中有一个主键序列列,此图中未显示)

在上表中,除了通过插入前每行触发器自动填充的“时间索引”之外,所有列都是通过查询输入的

这是创建相同表(没有任何值)的代码,因此每个人都可以使用PostgreSQL查询面板创建它

    CREATE TABLE table_ebscb_spa_log04
(
  pcnum smallint,
  stmtserial integer NOT NULL DEFAULT nextval('table_ebscb_spa_log04_stmtnum_seq'::regclass),
  fn_name character varying,
  "time" timestamp without time zone,
  time_elapse character varying,
  time_type character varying,
  time_index real,
  CONSTRAINT table_ebscb_spa_log04_pkey PRIMARY KEY (stmtserial)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE table_ebscb_spa_log04
  OWNER TO postgres;
我几乎已经完成了触发器的第一部分和第二部分,但我想知道在进入第三部分之前我是否采取了正确的方法

触发器的第一部分生成表格图像中每个红色高亮显示的方块,换句话说,它会这样做

根据每行的
fn\u name
time\u type
列的插入值,在时间索引列中插入一个数字

如果两者(
fn\u name
time\u type
)的组合(例如检查邮件-开始)在前面(上文)的任何行中都不存在,则在
时间索引
列中插入1

如果两个(
fn_name
time_type
)的组合确实存在于前面(上面)的某一行中,则在
time_index
列中插入前面(上面)匹配的数字后面的数字

触发器的第二部分生成表格图像中每一个绿色高亮显示的正方形,换句话说,它就是这样做的

根据每行“fn_name”和“time_type”列的插入值,在“time_index”列中插入一个数字

如果在时间类型列中插入“Lap”,则自动将同一行的时间索引填充到插入“Lap”的行中,数字与上一个(以上)时间索引单元格的数字相同,其中时间类型为“开始”,fn名称为;后跟一个点;然后是前一个time_索引单元格(其中time_type和fn_name=为插入“Lap”的行)中小数点后的数字,该数字不在(上方)任何time_type='Start'和fn_name=为插入“Lap”的行之前。如果没有人,则从1开始计数(因此它将是0.1)

这就是我到目前为止所做的。。。(请注意我在ELSE IF之后犯的错误)

以下是创建触发器的代码:

CREATE TRIGGER timelog
    BEFORE INSERT ON table_ebscb_spa_log04
    FOR EACH ROW
    EXECUTE PROCEDURE timelog();
现在,触发器的第三部分在表格图像中生成蓝色高亮显示的方块,但也会影响绿色高亮显示的squere的操作方式,换句话说,它会这样做

根据每行“fn_name”和“time_type”列的插入值,在“time_index”列中插入一个数字。 如果在time_type列中插入了Break,则自动将同一行的time_索引单元格填充到插入“Break”的行中,数字与上一个(以上)time_索引单元格的数字相同,其中time_type=开始,fn_name=结束;后跟一个点;然后是前一个time_索引单元格(其中time_type和fn_name=为插入“Break”的行)中小数点后的数字,该数字不在(上方)time_type=“Start”和“fn_name”为插入“Break”的行的任何单元格之前。如果没有人,那么从1开始计算

希望一些优秀的PostgreSQL程序员同事能帮我一把。我读过很多postgres的文档章节,没有任何线索


感谢高级。

基于前两个要求,触发器本身没有问题,但您可以大大简化:

CREATE OR REPLACE FUNCTION timelog() RETURNS trigger AS $BODY$
DECLARE
  t_ix real;
BEGIN
  -- First check if you need to change NEW at all
  IF (NEW.time_type = 'Start') OR (NEW.time_type = 'Lap') THEN
    -- Now perform the expensive lookup for either of 'Start' or 'Lap'
    SELECT time_index INTO t_ix
    FROM table_ebscb_spa_log04
    WHERE fn_name = NEW.fn_name
      AND (time_type = 'Start' OR time_type = 'Lap')
    ORDER BY stmtserial DESC LIMIT 1;

    IF NOT FOUND THEN
      -- Nothing found, so NEW.time_index := 1
      NEW.time_index := 1; 
    ELSIF NEW.time_type = 'Start' THEN 
      -- Start new index for fn_name, discard any fractional part, then increment
      NEW.time_index := floor(t_ix) + 1; 
    ELSE
      -- Continue the lap, increment NEW.time_index
      NEW.time_index := t_ix + 0.1; 
    END IF;
  END IF;
  RETURN NEW;
END; $BODY$ LANGUAGE plpgsql;
然而,有一种更简单的方法,它也可以毫无问题地满足第三个需求。与查看“时间索引”值不同,您应该查看“时间”值,因为“时间索引”是基于以下内容:

CREATE OR REPLACE FUNCTION timelog() RETURNS trigger AS $BODY$
DECLARE
  t_ix real;
BEGIN
  -- Find the most recent entry for the same "fn_name" as the new record
  SELECT time_index INTO t_ix
  FROM table_ebscb_spa_log04
  WHERE fn_name = NEW.fn_name
  ORDER BY time DESC LIMIT 1;

  -- Nothing found, so NEW.time_index := 1
  IF NOT FOUND THEN
    NEW.time_index := 1;
    RETURN NEW;
  END IF;

  -- Some record exists, so update "time_index" based on previous record
  CASE NEW.time_type 
    WHEN 'Start' THEN 
      -- Start new index for fn_name, discard any fractional part, then increment
      NEW.time_index := floor(t_ix) + 1; 
    WHEN 'Lap' THEN
      -- Continue the lap, increment NEW.time_index
      NEW.time_index := t_ix + 0.1; 
    ELSE
      -- Break, find previous break or start, increment by 0.1
      SELECT time_index + 0.1 INTO NEW.time_index
      FROM table_ebscb_spa_log04
      WHERE fn_name = NEW.fn_name
        AND (time_type = 'Start' OR time_type = 'Break')
      ORDER BY time DESC LIMIT 1;
  END CASE;

  RETURN NEW;
END; $BODY$ LANGUAGE plpgsql;
这实现了您的逻辑,但请注意存在一些潜在的陷阱:

  • 如果在“开始”之前插入“圈”或“断”怎么办
  • 如果在“开始”之后有9个以上的“fn_name”事件(“time_index”小数部分将滚动到下一个整数),该怎么办

当然,如果您的数据模型允许,您可以完全忘记“时间索引”字段和触发器,在视图中动态生成它(与“时间流逝”相同)。

对于上下文,读者应该看到前面的问题,不是真的,我提出了这个问题,因此它总结了前面问题中的所有信息。谢谢Patrick,确实更简单,但在第一次测试中,您的代码不起作用,所以我只是在末尾添加了一个额外的“END IF”,然后它就起作用了。尽管如此,我还是要道歉,因为我似乎忘记提及触发器的第三部分,这可能会影响孔触发器代码,请检查我的编辑。谢谢,伙计。
ELSE如果需要
ELSIF
,请参阅更新的代码。但是如果你不能正确地提出问题,你就不会得到正确的答案。“触发的第三部分”在您的编辑中我一点也不清楚。对不起,Patrick,我刚刚完成编辑,我真的想避免重新发布,所以我只是编辑了一下。很抱歉,我上传的第一个代码中有一个错误,现在,编辑的代码显示了错误,但无论如何,应该很容易抛出错误消息。所以我只需要帮助我认识到你的方法是否能很好地处理“触发的第三部分”,或者我是否应该继续使用我的方法?谢谢你,老兄。
CREATE OR REPLACE FUNCTION timelog() RETURNS trigger AS $BODY$
DECLARE
  t_ix real;
BEGIN
  -- Find the most recent entry for the same "fn_name" as the new record
  SELECT time_index INTO t_ix
  FROM table_ebscb_spa_log04
  WHERE fn_name = NEW.fn_name
  ORDER BY time DESC LIMIT 1;

  -- Nothing found, so NEW.time_index := 1
  IF NOT FOUND THEN
    NEW.time_index := 1;
    RETURN NEW;
  END IF;

  -- Some record exists, so update "time_index" based on previous record
  CASE NEW.time_type 
    WHEN 'Start' THEN 
      -- Start new index for fn_name, discard any fractional part, then increment
      NEW.time_index := floor(t_ix) + 1; 
    WHEN 'Lap' THEN
      -- Continue the lap, increment NEW.time_index
      NEW.time_index := t_ix + 0.1; 
    ELSE
      -- Break, find previous break or start, increment by 0.1
      SELECT time_index + 0.1 INTO NEW.time_index
      FROM table_ebscb_spa_log04
      WHERE fn_name = NEW.fn_name
        AND (time_type = 'Start' OR time_type = 'Break')
      ORDER BY time DESC LIMIT 1;
  END CASE;

  RETURN NEW;
END; $BODY$ LANGUAGE plpgsql;