首页 文章

如何在PostgreSQL中进行更新加入?

提问于
浏览
386

基本上,我想这样做:

update vehicles_vehicle v 
    join shipments_shipment s on v.shipment_id=s.id 
set v.price=s.price_per_vehicle;

我很确定它可以在MySQL(我的背景)中工作,但它似乎不适用于postgres . 我得到的错误是:

ERROR:  syntax error at or near "join"
LINE 1: update vehicles_vehicle v join shipments_shipment s on v.shi...
                                  ^

当然有一种简单的方法可以做到这一点,但我找不到合适的语法 . 那么,我如何在PostgreSQL中编写这个?

6 回答

  • 91

    UPDATE syntax是:

    [ WITH [ RECURSIVE ] with_query [, ...] ]
    UPDATE [ ONLY ] table [ [ AS ] alias ]
        SET { column = { expression | DEFAULT } |
              ( column [, ...] ) = ( { expression | DEFAULT } [, ...] ) } [, ...]
        [ FROM from_list ]
        [ WHERE condition | WHERE CURRENT OF cursor_name ]
        [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
    

    在你的情况下,我认为你想要这个:

    UPDATE vehicles_vehicle AS v 
    SET price = s.price_per_vehicle
    FROM shipments_shipment AS s
    WHERE v.shipment_id = s.id
    
  • 103

    让我通过我的例子再解释一下 .

    任务:正确的信息,其中abiturients(即将离开中学的学生)早些时候向大学提交申请,而不是他们获得学校证书(是的,他们获得的证书早于他们颁发的证书(通过指定的证书日期) . 所以,我们将增加申请提交日期以适应证书签发日期 .

    从而 . 下一个类似MySQL的声明:

    UPDATE applications a
    JOIN (
        SELECT ap.id, ab.certificate_issued_at
        FROM abiturients ab
        JOIN applications ap 
        ON ab.id = ap.abiturient_id 
        WHERE ap.documents_taken_at::date < ab.certificate_issued_at
    ) b
    ON a.id = b.id
    SET a.documents_taken_at = b.certificate_issued_at;
    

    以这种方式成为类似PostgreSQL的

    UPDATE applications a
    SET documents_taken_at = b.certificate_issued_at         -- we can reference joined table here
    FROM abiturients b                                       -- joined table
    WHERE 
        a.abiturient_id = b.id AND                           -- JOIN ON clause
        a.documents_taken_at::date < b.certificate_issued_at -- Subquery WHERE
    

    正如您所看到的,原始子查询 JOINON 子句已成为 WHERE 条件之一,由 AND 与其他条件结合,这些条件已从子查询中移除而没有任何更改 . 并且不再需要 JOIN 表(就像在子查询中一样) .

  • 39

    Mark Byers的答案在这种情况下是最佳的 . 虽然在更复杂的情况下,您可以使用返回rowid和计算值的select查询,并将其附加到更新查询,如下所示:

    with t as (
      -- Any generic query which returns rowid and corresponding calculated values
      select t1.id as rowid, f(t2, t2) as calculatedvalue
      from table1 as t1
      join table2 as t2 on t2.referenceid = t1.id
    )
    update t1
    set value = t.calculatedvalue
    from t
    where id = t.rowid
    

    此方法允许您开发和测试您的选择查询,并分两步将其转换为更新查询 .

    因此,在您的情况下,结果查询将是:

    with t as (
        select v.id as rowid, s.price_per_vehicle as calculatedvalue
        from vehicles_vehicle v 
        join shipments_shipment s on v.shipment_id = s.id 
    )
    update vehicles_vehicle
    set price = t.calculatedvalue
    from t
    where id = t.rowid
    

    请注意,列别名是必需的,否则PostgreSQL会抱怨列名的含糊不清 .

  • 625

    对于那些真正想做 JOIN 的人,你也可以使用:

    UPDATE a
    SET price = b_alias.unit_price
    FROM      a AS a_alias
    LEFT JOIN b AS b_alias ON a_alias.b_fk = b_alias.id
    WHERE a_alias.unit_name LIKE 'some_value' 
    AND a.id = a_alias.id;
    

    如果需要,您可以在等号右侧的 SET 部分中使用a_alias . 等号左侧的字段不需要表引用,因为它们被认为来自原始的"a"表 .

  • 5

    开始了:

    update vehicles_vehicle v
    set price=s.price_per_vehicle
    from shipments_shipment s
    where v.shipment_id=s.id;
    

    简单,因为我可以做到 . 多谢你们!

    也可以这样做:

    update vehicles_vehicle 
    set price=s.price_per_vehicle
    from vehicles_vehicle v
    join shipments_shipment s on v.shipment_id=s.id;
    

    但是那时你已经有两次车辆表,并且你只允许别名一次,你不能在“set”部分使用别名 .

  • 0

    这是一个简单的SQL,它使用Name中的Middle_Name字段更新Name3表上的Mid_Name:

    update name3
    set mid_name = name.middle_name
    from name
    where name3.person_id = name.person_id;
    

相关问题