Postgres 默认值是两条记录的差值
Postgres default value is the difference of two records
我有一个 postgres table 包含以下列:id、text、timestamp、diff
id是自动生成的,文本是插入的,时间戳是默认的,diff应该是当前记录的时间戳和前一条记录的时间戳(prev by id)的差值,如果前一天和实际是同一天,如果不是,应该是0. 所以所有列都是在插入文本时自动生成的。
你知道有什么方法可以通过表达式等使这个差异成为默认值吗?我是 sql.
的新手
谢谢。
为此你可以使用触发器:
CREATE TABLE tbl (
id int,
ts timestamp DEFAULT now(), -- 1
diff float -- 2
);
CREATE FUNCTION set_ts_diff() RETURNS trigger AS $$
DECLARE
_last_ts timestamp;
BEGIN
SELECT COALESCE(MAX(ts), NEW.ts) FROM tbl INTO _last_ts; -- 3
IF (NEW.ts::date = _last_ts::date) THEN -- 4
NEW.diff := EXTRACT(EPOCH FROM NEW.ts - _last_ts); -- 5
ELSE
NEW.diff := 0;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tr_set_ts_diff BEFORE INSERT ON tbl -- 6
FOR EACH ROW EXECUTE PROCEDURE set_ts_diff();
- 创建您的 table。
ts
默认获取当前时间戳 (now()
)。
diff
将用作以秒为单位的差异。因为可以在一秒钟内完成两次插入,所以 float
类型会有所帮助。另一种方法可能是 interval
类型,它是时间戳减法的默认类型(参见第 5 点)
- 触发器需要一个触发器函数来知道事件被触发后要做什么。在这个函数中我们得到最后一个
ts
存储在tbl
之前。如果不存在行,则在 COALESCE
的帮助下采用当前 ts
(NEW
是要插入的当前行)
- 然后检查最后一个和当前
ts
是否具有相同的日期(通过将两个时间戳都转换为 date
进行检查)。
- 如果是,计算导致类型
interval
的差异。要从 interval
中获取秒数,请使用 EXTRACT(EPOCH FROM ...)
.
- 创建触发器:在保留新行 (
ON BEFORE INSERT
) 之前执行触发器函数并设置 NEW.diff
列。
注意事项:
您应该勉强保留以后可以计算的数据。可以借助 LAG
window function, which takes the value of the previous row to the current one (demo):
计算两个时间戳之间的差异
SELECT
ts,
EXTRACT(EPOCH FROM ts - lag(ts) OVER (ORDER BY ts)) as diff
FROM
tbl;
如果必须删除一行,则可以看出硬存储差异的缺点。下一个的差异现在有一个错误的值,因为它的引用丢失了。您的数据可能会变得不一致。
我会去 VIEW
CREATE OR REPLACE VIEW v_tbl AS
SELECT id,
txt,
tstamp,
coalesce ( extract ( epoch FROM tstamp - LAG(tstamp)
OVER(PARTITION BY date_trunc('day',tstamp) ORDER BY id)),0)
FROM tbl;
我有一个 postgres table 包含以下列:id、text、timestamp、diff id是自动生成的,文本是插入的,时间戳是默认的,diff应该是当前记录的时间戳和前一条记录的时间戳(prev by id)的差值,如果前一天和实际是同一天,如果不是,应该是0. 所以所有列都是在插入文本时自动生成的。 你知道有什么方法可以通过表达式等使这个差异成为默认值吗?我是 sql.
的新手谢谢。
为此你可以使用触发器:
CREATE TABLE tbl (
id int,
ts timestamp DEFAULT now(), -- 1
diff float -- 2
);
CREATE FUNCTION set_ts_diff() RETURNS trigger AS $$
DECLARE
_last_ts timestamp;
BEGIN
SELECT COALESCE(MAX(ts), NEW.ts) FROM tbl INTO _last_ts; -- 3
IF (NEW.ts::date = _last_ts::date) THEN -- 4
NEW.diff := EXTRACT(EPOCH FROM NEW.ts - _last_ts); -- 5
ELSE
NEW.diff := 0;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tr_set_ts_diff BEFORE INSERT ON tbl -- 6
FOR EACH ROW EXECUTE PROCEDURE set_ts_diff();
- 创建您的 table。
ts
默认获取当前时间戳 (now()
)。 diff
将用作以秒为单位的差异。因为可以在一秒钟内完成两次插入,所以float
类型会有所帮助。另一种方法可能是interval
类型,它是时间戳减法的默认类型(参见第 5 点)- 触发器需要一个触发器函数来知道事件被触发后要做什么。在这个函数中我们得到最后一个
ts
存储在tbl
之前。如果不存在行,则在COALESCE
的帮助下采用当前 - 然后检查最后一个和当前
ts
是否具有相同的日期(通过将两个时间戳都转换为date
进行检查)。 - 如果是,计算导致类型
interval
的差异。要从interval
中获取秒数,请使用EXTRACT(EPOCH FROM ...)
. - 创建触发器:在保留新行 (
ON BEFORE INSERT
) 之前执行触发器函数并设置NEW.diff
列。
ts
(NEW
是要插入的当前行)
注意事项:
您应该勉强保留以后可以计算的数据。可以借助 LAG
window function, which takes the value of the previous row to the current one (demo):
SELECT
ts,
EXTRACT(EPOCH FROM ts - lag(ts) OVER (ORDER BY ts)) as diff
FROM
tbl;
如果必须删除一行,则可以看出硬存储差异的缺点。下一个的差异现在有一个错误的值,因为它的引用丢失了。您的数据可能会变得不一致。
我会去 VIEW
CREATE OR REPLACE VIEW v_tbl AS
SELECT id,
txt,
tstamp,
coalesce ( extract ( epoch FROM tstamp - LAG(tstamp)
OVER(PARTITION BY date_trunc('day',tstamp) ORDER BY id)),0)
FROM tbl;