根据其他列OLD INSERT

时间:2015-06-24 06:16:21

标签: postgresql triggers autofill

在PostgreSQL中我有这个表...(最左侧有一个主键串行列“stmtserial”,此图中未显示)

enter image description here

在上表中,所有列都是通过查询输入的,“time_index”除外,它通过BEFORE INSERT,PER-ROW触发器自动填充。

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

    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;

我几乎完成了触发器的前n秒部分,但我想知道在进入第三部分之前我是否采取了正确的方法。

触发器的第一部分会在表格图像中生成每个红色突出显示的方块,换句话说就是这样做...

根据每行fn_nametime_type列的INSERTed值,在time_index列中插入一个数字。

如果两者(fn_nametime_type)组合(例如,检查邮件 - 开始)在(上)之前的任何行中不存在,则在{{1}中插入1列。

Elif(time_indexfn_name)执行在(上面)之前的某行中确实存在的组合,然后在{上一个(上面)匹配中的数字后面插入数字{ {1}}栏。

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

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

如果在time_type列中插入'Lap',则自动填充同一行的time_index,其编号与上一个(上面)time_index单元格相同WHERE time_type ='Start'和fn_name =到'Lap'被插入的行;然后是一个点;并且后面是前一个time_index单元格中小数点后面的数字WHERE time_type和fn_name =指向'Lap'被插入的行中的数字,它们不在任何行之前(上面)WHERE time_type ='Start'和fn_name =到'Lap'被插入的行中的那个。如果没有人,则从1开始计数(因此它将为0.1)。

所以,这是我到目前为止所做的......(请注意我之后的错误)

time_type

这是创建触发器的代码:

time_index

现在,触发器的第三部分会在表格图像中生成蓝色突出显示的方块,但也会影响绿色突出显示的squere的操作方式,换句话说就是这样做...

根据每行中“fn_name”和“time_type”列的INSERTed值,在“time_index”列中插入一个数字。 如果在time_type列中插入了Break,则自动填充同一行的time_index单元格,其编号与上一个(上面)time_index单元格相同WHERE time_type = Start和fn_name =到'Break'所在行中的那个插入;然后是一个点;并且后面是前一个time_index单元格中的十进制数字后面的数字WHERE time_type和fn_name =指向“Break”被插入的行中的数字,不在任何单元格之前(上方)WHERE time_type ='Start'和' fn_name'=到'Break'被插入的行中的那个。如果没有人,则从1开始计算。

希望一些优秀的PostgreSQL同事程序员可以帮我一臂之力。我已经阅读了很多postgres文档章节,没有任何线索。

谢谢高级。

1 个答案:

答案 0 :(得分:1)

根据前两个要求,您的触发器本身没有任何问题,但您可以大大简化它:

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;

然而,有一种更简单的方法,它也可以满足第三个要求而没有问题。而不是看" time_index"值,你应该看看"时间"价值,因为那是" time_index"基于:

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;

这实现了你的逻辑,但请注意存在一些潜在的缺陷:

  • 如果您插入' Lap'或者打破'在开始'?
  • 之前
  • 如果您有超过9" fn_name"该怎么办? “开始”之后的活动' (" time_index"小数部分将转到下一个整数)?

你当然可以忘记" time_index"字段和触发器一起在视图中动态生成它,如果您的数据模型允许它(与#34; time_elapse"相同)。