【问题标题】:SQL Update or Create RowSQL 更新或创建行
【发布时间】:2021-12-24 11:26:40
【问题描述】:

我在 PostgreSQL 中有一张表需要修改,该表如下所示:

 name | value1 | value2 | date         
--------+-------+--------+---------
 Jonh |        |  0.15  | 2021-12-23 00:00:00
 Jonh |  0.14  |  0.76  | 2021-12-22 00:00:00
 Jonh |  0.19  |  0.87  | 2021-12-21 00:00:00
 Jonh |  0.13  |  0.11  | 2021-12-15 00:00:00
 Bob  |  0.12  |  0.23  | 2021-12-15 00:00:00

拥有namedatevalue1value2,我需要创建一个声明:

  1. 检查是否存在带有namedate 的行(有一个约束键,因此两个值只能有一行)
  2. 在此行中插入值 value1value2(更新行值,虽然最初此列在行中为空)。

我需要在不同的时间设置value1value2,所以我需要找到一种创建新行或更新当前行的方法,我使用this answer创建创建或更新行语句,你是怎么做到的?

编辑

场景 1,作为输入,我将有参数:

name='Jonh'
value1 = 0.5
date = '2021-12-23 00:00:00'

在这种情况下,具有此名称和日期的行已经存在,因此它只会更新value1 的值。 决赛桌:

 name | value1 | value2 | date         
--------+-------+--------+---------
 Jonh |  0.5   |  0.15  | 2021-12-23 00:00:00
 Jonh |  0.14  |  0.76  | 2021-12-22 00:00:00
 Jonh |  0.19  |  0.87  | 2021-12-21 00:00:00
 Jonh |  0.13  |  0.11  | 2021-12-15 00:00:00
 Bob  |  0.12  |  0.23  | 2021-12-15 00:00:00

场景 2,作为我的输入:

name='Tim'
value2 = 1
date = '2021-12-23 00:00:00'

因为没有具有此名称和日期的行,它将创建一个新行,分配value2 并为value1 设置一个NULL 值。 决赛桌:

 name | value1 | value2 | date         
--------+-------+--------+---------
 Tim  |        |  1     | 2021-12-23 00:00:00
 Jonh |        |  0.15  | 2021-12-23 00:00:00
 Jonh |  0.14  |  0.76  | 2021-12-22 00:00:00
 Jonh |  0.19  |  0.87  | 2021-12-21 00:00:00
 Jonh |  0.13  |  0.11  | 2021-12-15 00:00:00
 Bob  |  0.12  |  0.23  | 2021-12-15 00:00:00

【问题讨论】:

  • 根据此示例数据,您期望的输出是什么?
  • @TimBiegeleisen 我已经更新了我的问题以添加一些预期的输出

标签: sql postgresql insert sql-update


【解决方案1】:

SQL 中的“更新或插入”通常称为“Upsert”、“Merge”或“Replace”。 检查 pgsql 文档: https://www.postgresqltutorial.com/postgresql-upsert/ 并改编它的例子

INSERT INTO customers (name, email)
VALUES('Microsoft','hotline@microsoft.com') 
ON CONFLICT (name) 
DO 
   UPDATE SET email = EXCLUDED.email || ';' || customers.email;

满足您的需求

【讨论】:

    【解决方案2】:

    您可以使用 INSERT ON CONFLICT 语法。

    但它预计当有重复时会发生冲突。

    因此,对于您的表,它需要(名称、日期)上的主键或唯一索引

    示例

    create table your_table (
     name varchar(30),
     value1 decimal(10,2),
     value2 decimal(10,2),
     date date
    );
    
    insert into your_table (name, value1, value2, date) values
    ('Jonh Deo', null, 0.15, '2021-12-23'), 
    ('Jonh Deo', 0.14, 0.76, '2021-12-22'), 
    ('Jonh Deo', 0.19, 0.87, '2021-12-21'), 
    ('Jonh Deo', 0.13, 0.11, '2021-12-15'), 
    ('Bob Savage', 0.12, 0.23, '2021-12-15');
    
    -- trying to insert a conflicting duplicate
    INSERT INTO your_table (name, value1, date)
    VALUES 
    ('Jonh Deo', 0.5, '2021-12-23')
    ON CONFLICT (name, date) 
    DO UPDATE SET value1 = EXCLUDED.value1;
    
    错误:没有与 ON CONFLICT 规范匹配的唯一或排除约束
    -- maybe it needs a PK or unique index? 
    ALTER TABLE your_table
    ADD primary key (name, date);
    
    -- trying to insert a conflicting duplicate again
    INSERT INTO your_table (name, value1, date)
    VALUES 
    ('Jonh Deo', 0.5, '2021-12-23')
    ON CONFLICT (name, date) 
    DO UPDATE SET value1 = EXCLUDED.value1;
    
    1 行受影响
    -- now with completely original records
    INSERT INTO your_table (name, value1, value2, date)
    VALUES 
    ('Tim Bok Toh', null, 1.0, '2021-12-23'), 
    ('Tim Bok Toh',  0.6, 1.2, '2021-12-24')
    ON CONFLICT (name, date) 
    DO UPDATE SET value1 = EXCLUDED.value1
                , value2 = EXCLUDED.value2;
    
    2 行受影响
    select * from your_table
    
    name value1 value2 date
    Jonh Deo 0.14 0.76 2021-12-22
    Jonh Deo 0.19 0.87 2021-12-21
    Jonh Deo 0.13 0.11 2021-12-15
    Bob Savage 0.12 0.23 2021-12-15
    Jonh Deo 0.50 0.15 2021-12-23
    Tim Bok Toh null 1.00 2021-12-23
    Tim Bok Toh 0.60 1.20 2021-12-24

    dbfiddle here

    上的演示

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-20
      • 2020-10-31
      • 1970-01-01
      • 2015-11-19
      • 2015-01-26
      • 1970-01-01
      • 2014-01-12
      • 1970-01-01
      相关资源
      最近更新 更多