代码之家  ›  专栏  ›  技术社区  ›  William

Postgresql冲突更新整行

  •  0
  • William  · 技术社区  · 2 年前

    我有一张名为 customers ,具有许多列: 'id', 'name', 'age', 'weight', 'hight', 'blood', 'sex', 'last name', 'datetime'

    我想在插入之前添加一个检查逻辑,即如果日期时间已经存在,那么更新/覆盖整个现有行。

    我的代码:

    INSERT INTO customers (id,name,age,weight,hight,blood,sex,last name,datetime)
    VALUES('1','2','3','4','5','6','7','8','2022-12-30') 
    ON CONFLICT (datetime) 
    DO 
       UPDATE SET name = EXCLUDED.name || ';' || customers.name;
       ....
       UPDATE SET name = EXCLUDED.datetime || ';' || customers.datetime;
    

    因为该表有许多列,并且如果 datetime 已经存在,那么有没有更简单的方法来代替 更新集 对于每列?

    0 回复  |  直到 2 年前
        1
  •  1
  •   Schwern    2 年前

    可以 做这个。。。

    INSERT INTO customers (id,name,age,weight,hight,blood,sex,last name,datetime)
    VALUES('1','2','3','4','5','6','7','8','2022-12-30') 
    ON CONFLICT (datetime) 
    DO 
       UPDATE SET
         name = EXCLUDED.name || ';' || customers.name,
         datetime = EXCLUDED.datetime || ';' || customers.datetime,
         ...and so on...
    

    但这是个坏主意,原因有很多。

    1. 您必须将所有内容存储为varchar。您没有类型保护,无法使用任何功能。
    2. 搜索将是复杂而低效的,因为每次搜索都必须首先解析值。
    3. 数据的大小将不断增长。
    4. 没有指示何时更新这些值。

    假设这是为了记录更改以便以后进行审核,请使用审核表来存储旧值。这可以是一个特定的表,逐列镜像原始的列,但使用单个表和JSON更容易。

    create table audits (
      id bigserial primary key,
      table_name text not null,
      data jsonb not null,
      event text not null,
      changed_at timestamp default(current_timestamp)
    )
    

    然后,您可以让触发器在每次更改时写入审核表。 event 可用于记录是插入、更新还是删除。您还可以记录用户所做的更改。

        2
  •  1
  •   Mocas    2 年前

    使用合并

    这里有很好的例子 https://www.sqlshack.com/understanding-the-sql-merge-statement/

    您的目标表将是 Customers 表,并且您将需要创建一个具有要插入/更新的记录的虚拟表,让我们称之为 Record

    MERGE Customers AS Target
    USING Record AS Source
    ON Source.datetime = Target.datetime And id Source.id = Target.id
    
    -- For Inserts
    WHEN NOT MATCHED BY Target THEN
        -- insert the record here
    
    -- For Updates
    WHEN MATCHED THEN UPDATE SET
        -- Update here
    

    解决方案不完整,您需要将您的值放入一个虚拟表中,并更新insert和update语句,但您已经明白了。