根据其他列在列中插入实数 OLD INSERTs

Posted

技术标签:

【中文标题】根据其他列在列中插入实数 OLD INSERTs【英文标题】:INSERT a real number in a column based on other columns OLD INSERTs 【发布时间】:2015-06-24 06:16:20 【问题描述】:

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

在上表中,所有列都是通过查询输入的,除了“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)都进行了组合(例如,检查邮件 - 开始),但在之前(上)的任何行中都不存在,则在 time_index 列中插入 1。

Elif 两者(fn_nametime_type)都做了一个在前面(上面)的某行中确实存在的组合,然后在 time_index 列中插入前一个(上面)匹配中的数字后面的数字。

触发器的第二部分在表格图像中生成每个绿色突出显示的正方形,换句话说,它执行此操作...

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

如果在 time_type 列中插入了“Lap”,则自动填充同一行的 time_index,其编号与上一个 time_index 单元格相同,其中 time_type = 'Start' 和 fn_name = 到插入“Lap”的行;后跟一个点;然后是前一个 time_index 单元格中小数点后的数字 WHERE time_type 和 fn_name = 到插入“Lap”的行中的数字,它们不在任何行之前(上方)WHERE time_type = 'Start' 和 fn_name = 插入到“Lap”行中的那个。如果没有人,则从 1 开始计数(所以应该是 0.1)。

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

CREATE OR REPLACE FUNCTION timelog()
  RETURNS trigger AS
$BODY$
DECLARE
t_ix real;
n int;

BEGIN
IF NEW.time_type = 'Start' THEN
    SELECT t.time_index FROM table_ebscb_spa_log04 t WHERE t.fn_name = NEW.fn_name AND t.time_type = 'Start' ORDER BY t.stmtserial DESC LIMIT 1 INTO t_ix;
      GET DIAGNOSTICS n = ROW_COUNT;
        IF (n = 0) THEN 
        t_ix := 1; --this is ok, here it's really necessary to set it to 1
        ELSE
        t_ix := t_ix + 1;
        END IF;

ELSE 
    IF NEW.time_type = 'Lap' THEN 
        SELECT t.time_index  FROM table_ebscb_spa_log04 t WHERE t.fn_name = NEW.fn_name AND (t.time_type = 'Start' OR time_type = 'Lap') ORDER BY t.stmtserial DESC LIMIT 1 INTO t_ix;
          GET DIAGNOSTICS n = ROW_COUNT;
            IF (n = 0) THEN 
            t_ix := 1; --!!!HERE I MADE A MISTAKE (SORRY) IT SHOULDN'T BE SET TO 1, IT SHOULD THROW AN ERROR MESSAGE 'There isn't any previous same fn_name with time_type Start';
            ELSE 
            t_ix := t_ix + 0.1;
            END IF;
  END IF;
END IF;
NEW.time_index = t_ix;
return NEW;
END
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION timelog()
  OWNER TO postgres;

这是创建触发器的代码:

CREATE TRIGGER timelog
    BEFORE INSERT ON table_ebscb_spa_log04
    FOR EACH ROW
    EXECUTE PROCEDURE timelog();

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

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

希望一些优秀的 PostgreSQL 程序员可以帮助我。我已经阅读了许多 postgres 文档章节,但没有任何线索。

感谢高级。

【问题讨论】:

关于上下文,读者应该看前面的问题***.com/q/30942869/398670 不是真的,我提出了这个问题,所以它总结了上一个问题中的所有信息。 【参考方案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”值,因为这是“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;

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

如果在“开始”之前插入“圈”或“休息”会怎样? 如果在“开始”之后有超过 9 个“fn_name”事件怎么办(“time_index”小数部分将滚动到下一个整数)?

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

【讨论】:

谢谢帕特里克,确实更简单,但是在第一次测试中你的代码不起作用,所以我只是在最后添加了一个额外的“END IF”,然后它就起作用了。尽管如此我还是要道歉,因为我似乎忘了提到触发器的第三部分,这可能会影响洞触发器代码,请检查我的编辑。谢谢大佬。 ELSE IF 必须是 ELSIF,请参阅更新后的代码。但是,如果您不能正确地提出问题,您将不会得到正确的答案。从您的编辑中,我根本不清楚“触发器的第三部分”。 对不起Patrick,我刚刚编辑完,我真的很想避免重新发布,所以我只是编辑了。对不起。 我上传的第一个代码有错误,现在编辑的代码显示错误,但无论如何应该很容易抛出错误消息。所以我只需要帮助来确定您的方法是否可以很好地与“触发器的第三部分”一起使用,或者我是否应该继续使用我的方法?谢谢先进的人。

以上是关于根据其他列在列中插入实数 OLD INSERTs的主要内容,如果未能解决你的问题,请参考以下文章

在列中插入默认值(访问数据库)

在列中插入条件行

如何使用python在列中插入日期

插入数据并在列中添加前一行数据

如何使用 Spark 数据框中的 lit 在列中插入值?

Python QTableView:如何在列中插入项目