PostgreSQL多重upsert没有重复出现错误

时间:2017-10-12 11:27:53

标签: sql postgresql upsert

我使用PostgreSQL 9.5,Ubuntu 16.04

我有表:

CREATE TABLE IF NOT EXISTS candles_1m(
   timestamp      REAL PRIMARY KEY,
   open      REAL,
   close      REAL,
   high      REAL,
   low      REAL,
   volume      REAL
);

然后我尝试多次upsert(没有重复的时间戳' - 主键):

INSERT INTO candles_1m (
  timestamp, open, close, high, low, volume
  ) VALUES 
  (1507804800, 5160, 5158.7, 5160, 5158.7, 5.40608574), 
  (1507804740, 5157.5, 5160, 5160, 5156.1, 39.03357813), 
  (1507804680, 5156.5, 5157.4, 5157.4, 5156, 33.54458319), 
  (1507804620, 5151.3, 5156.5, 5157.5, 5151.2, 19.75590599)
  ON CONFLICT (timestamp)
  DO UPDATE SET
        open = EXCLUDED.open,
        close = EXCLUDED.close,
        high = EXCLUDED.high,
        low = EXCLUDED.low,
        volume = EXCLUDED.volume;

我收到并收到错误:

ERROR:  ON CONFLICT DO UPDATE command cannot affect row a second time
HINT:  Ensure that no rows proposed for insertion within the same command have duplicate constrained values.

我不明白为什么?我在那里没有重复!但我的下一步是创建一个请求,逐步添加(或更新)每一行(独立于重复项)。

2 个答案:

答案 0 :(得分:1)

来自the documentation:

  

实4字节变精度,不精确6位小数精度

你有两对相等的实数值:

select 
    1507804800::real = 1507804740::real as r1r2, 
    1507804680::real = 1507804620::real as r3r4

 r1r2 | r3r4 
------+------
 t    | t
(1 row)

使用精度更高的类型。

答案 1 :(得分:1)

正如其他人所指出的那样,这是因为您输入的两个值在转换为REAL时被截断为相同的值。

  

为什么?

因为浮点数在其范围内不具有统一的精度 - 接近零,它们可以更准确地表示非常小的分数,并且远非零,它们可以不准确地表示非常大的值。您的值高于精确表示每个整数的范围,因此无论何时插入它们,您的值都会有效地舍入到最接近的可表示值。

请注意,这不仅仅是重复问题,每次插入该表时实际上都会丢失数据。

  

如何解决?

选择a more suitable data type for your column。如果您的时间戳从不具有小数组件,则BigInt可能是合适的;否则,请阅读不同宽度浮点数的精度限制。或者你可能应该将它们转换为an appropriate date/time type,或许using to_timestamp

相关问题