ON CONFLICT(UUid,date_trunc(' day',timestamp))

时间:2018-01-23 08:33:33

标签: postgresql

在下面的代码中,这很有效,我想摆脱“mday”'并且在ON CONFLICT / ON CONSTRAINT中仅使用时间戳的日期部分但尚未找到解决方法。 HAd将我的希望寄托在一个排除约束EXCLUDE(fid WITH =,date_trunc(' day',ts)WITH =)但是这不起作用。

BEGIN;
DROP TABLE IF EXISTS flow;
CREATE TABLE flow ( 
    fid  UUid NOT NULL,
    fvol REAL[],
    ts   TIMESTAMP WITH TIME ZONE NOT NULL,
    mday DATE NOT NULL,
    UNIQUE (fid, mday)
);
COMMIT;

INSERT INTO flow (fid, fvol, ts, mday)
VALUES (
    'b55e9fbe-daea-4142-8843-5e5cf757b778', '{7}',
    '2019-06-26T19:12:00Z01', '2019-06-26'
)
ON CONFLICT (fid, mday)
DO UPDATE
SET fvol = flow.fvol || EXCLUDED.fvol, ts = EXCLUDED.ts;

1 个答案:

答案 0 :(得分:1)

您无法在表达式上创建唯一约束(例如unique (fid, (ts::date)),也无法使用它创建唯一索引(这对于ON CONFLICT就足够了。)

唯一索引将被拒绝:

  

错误:索引表达式中的函数必须标记为IMMUTABLE

这是因为(对于Postgres的一些内部原因),将时间戳转换为DATE并不是明确的。但是你可以通过创建一个不可变的函数来解决这个问题。

create function my_to_date(p_ts timestamp with time zone) 
  returns date
as $$
  select p_ts::date;
$$ 
language sql
immutable; --<< this makes the function usable in an index

完成后,您可以在表达式上创建唯一索引:

create unique index ix_unique_day on flow (fid, my_to_date(ts));

请注意,您无法使用该索引创建唯一的约束,但出于您的目的,这无关紧要。

唯一索引的表达式可用于ON CONFLICT部分:

INSERT INTO flow 
  (fid, fvol, ts)
VALUES 
  ('b55e9fbe-daea-4142-8843-5e5cf757b778', '{7}', '2019-06-26T19:12:00Z01')
ON CONFLICT (fid, my_to_date(ts))
DO UPDATE
  SET fvol = flow.fvol || EXCLUDED.fvol, ts = EXCLUDED.ts;