Postgres 9.5中的Upsert

时间:2015-12-08 18:51:53

标签: sql postgresql unique upsert postgresql-9.5

尝试进行upsert以维护用户第一个上次登录时间戳和平台。但是新引入的upsert(插入冲突)不允许插入select查询的输出。尝试使用但没有用。新插入是否支持插入查询输出并在主键冲突时更新现有字段。以下是使用的查询:

INSERT INTO user_first_last (UserId, FirstLoginDate, LastLoginDate,FirstLoginAmt,LastLoginAmt)
select id, fdd,  ldd,  fda,  lda from daily_activity as dp
ON CONFLICT (UserId)
DO UPDATE 
SET         FirstLoginAmt = case when dp.fdd < FirstLoginDate then dp.fda else FirstLoginAmt END,
            LastLoginAmt = case when dp.ldd > LastLoginDate then dp.lda else LastLoginAmt END,
        FirstLoginDate = case when dp.fdd < FirstLoginDate then dp.fdd else FirstLoginDate END,
            LastLoginDate = case when dp.ldd > LastLoginDate then dp.ldd else LastLoginDate END;

它抛出错误:

missing FROM-clause entry for table "dp"
ERROR:  missing FROM-clause entry for table "dp"
LINE 8: SET         FirstLoginAmt = case when dp.fdd < FirstLoginDate ...

使用excluded会再次出现错误:

INSERT INTO user_first_last (UserId, FirstLoginDate,LastLoginDate,FirstLoginAmt,LastLoginAmt) 
select id, fdd,  ldd,fda,  lda 
from daily_activity 
ON CONFLICT (UserId) 
DO UPDATE  
  SET FirstLoginAmt = case when excluded.fdd < FirstLoginDate then excluded.fda else FirstLoginAmt END, 
      LastLoginAmt = case when excluded.ldd > LastLoginDate then excluded.lda else LastLoginAmt END,FirstLoginDate = case when excluded.fdd < FirstLoginDate then excluded.fdd else FirstLoginDate END,
      LastLoginDate = case when excluded.ldd > LastLoginDate then excluded.ldd else LastLoginDate END;

错误:     错误:列excluded.fdd不存在

我尝试了以下内容,请在最后使用复制,这仍然是错误:

drop table daily_deposits;
create table daily_deposits
(   id int,
    fdd timestamp,
    ldd timestamp,
    fda double precision,
    lda double precision
);

insert into daily_deposits (id, fdd,  ldd,  fda, lda) values (1,'2015-12-01 08:10:50','2015-12-01 10:10:50', 10, 9);
insert into daily_deposits (id, fdd,  ldd,  fda, lda) values (1,'2015-12-02 10:10:50','2015-12-02 12:10:50', 10, 9);
insert into daily_deposits (id, fdd,  ldd,  fda, lda) values (1,'2015-12-04 04:10:50','2015-12-04 08:10:50', 15, 20);

insert into daily_deposits (id, fdd,  ldd,  fda, lda) values (2,'2015-12-01 08:10:50','2015-12-01 10:10:50', 5, 10);
insert into daily_deposits (id, fdd,  ldd,  fda, lda) values (2,'2015-12-02 10:10:50','2015-12-02 12:10:50', 6, 12);
insert into daily_deposits (id, fdd,  ldd,  fda, lda) values (2,'2015-12-03 04:10:50','2015-12-04 08:10:50', 9, 11);

commit;

select * from daily_deposits;

drop table user_first_last;
create table user_first_last
(   UserId int, 
    FirstLoginDate timestamp,
    LastLoginDate timestamp,
    FirstLoginAmt double precision,
    LastLoginAmt double precision
);


INSERT INTO user_first_last AS ufl (UserId, FirstLoginDate,LastLoginDate,FirstLoginAmt,LastLoginAmt) 
select id, fdd,  ldd,fda,  lda 
from daily_deposits 
ON CONFLICT (UserId) 
DO UPDATE  
  SET FirstLoginAmt = case when excluded.fdd < ufl.FirstLoginDate then excluded.fda else ufl.FirstLoginAmt END, 
      LastLoginAmt = case when excluded.ldd > ufl.LastLoginDate then excluded.lda else ufl.LastLoginAmt END,
      FirstLoginDate = case when excluded.fdd < ufl.FirstLoginDate then excluded.fdd else ufl.FirstLoginDate END,
      LastLoginDate = case when excluded.ldd > ufl.LastLoginDate then excluded.ldd else ufl.LastLoginDate END;

ERROR:  column excluded.fdd does not exist
LINE 6:   SET FirstLoginAmt = case when excluded.fdd < ufl.FirstLogi...
                                        ^
********** Error **********

ERROR: column excluded.fdd does not exist
SQL state: 42703
Character: 222

2 个答案:

答案 0 :(得分:3)

the documentation

  

ON CONFLICT DO UPDATE中的SET和WHERE子句可以使用表的名称(或别名)访问现有行,并使用特殊的排除表来建议插入行。

特殊记录exluded与表格user_first_last的类型相同。

insert into user_first_last as u
    (userid, firstlogindate,lastlogindate,firstloginamt,lastloginamt) 
    select id, fdd, ldd, fda, lda 
    from daily_activity 
on conflict (userid) 
    do update set
    firstloginamt = case 
        when excluded.firstlogindate < u.firstlogindate 
        then excluded.firstloginamt 
        else u.firstloginamt 
    end, 
    lastloginamt = case 
        when excluded.lastlogindate > u.lastlogindate 
        then excluded.lastloginamt 
        else u.lastloginamt 
    end,
    firstlogindate = case 
        when excluded.firstlogindate < u.firstlogindate 
        then excluded.firstlogindate 
        else u.firstlogindate 
    end,
    lastlogindate = case 
        when excluded.lastlogindate > u.lastlogindate 
        then excluded.lastlogindate 
        else u.lastlogindate 
    end;

答案 1 :(得分:1)

我也遇到了这个问题,并希望在其他正确答案中添加澄清信息。

'excluded'指的是您尝试插入的行被拒绝。

在此示例中,不同之处在于您需要引用excluded.firstlogindate而不是excluded.fdd,因为firstlogindate是插入时列的名称。