使用子查询更新postgres中的表行


301

使用postgres 8.4,我的目标是更新现有表:

CREATE TABLE public.dummy
(
  address_id SERIAL,
  addr1 character(40),
  addr2 character(40),
  city character(25),
  state character(2),
  zip character(5),
  customer boolean,
  supplier boolean,
  partner boolean

)
WITH (
  OIDS=FALSE
);

最初我使用插入语句测试了我的查询:

insert into address customer,supplier,partner
SELECT  
    case when cust.addr1 is not null then TRUE else FALSE end customer, 
    case when suppl.addr1 is not null then TRUE else FALSE end supplier,
    case when partn.addr1 is not null then TRUE else FALSE end partner
from (
    SELECT *
        from address) pa
    left outer join cust_original cust
        on (pa.addr1=cust.addr1 and pa.addr2=cust.addr2 and pa.city=cust.city 
            and pa.state=cust.state and substring(cust.zip,1,5) = pa.zip  )
    left outer join supp_original suppl 
        on (pa.addr1=suppl.addr1 and pa.addr2=suppl.addr2 and pa.city=suppl.city 
                and pa.state=suppl.state and pa.zip = substring(suppl.zip,1,5))
    left outer join partner_original partn
        on (pa.addr1=partn.addr1 and pa.addr2=partn.addr2 and pa.city=partn.city
                  and pa.state=partn.state and pa.zip = substring(partn.zip,1,5) )
where pa.address_id = address_id

作为新手,我无法转换为更新语句,即用select语句返回的值更新现有行。非常感谢您的帮助。


地址表中是否有任何类型的ID,可用于确定该行是否存在?
Andrey Adamovich

是的,我这样做,但是生成了它的sys。
stackover

Answers:


681

Postgres允许:

UPDATE dummy
SET customer=subquery.customer,
    address=subquery.address,
    partn=subquery.partn
FROM (SELECT address_id, customer, address, partn
      FROM  /* big hairy SQL */ ...) AS subquery
WHERE dummy.address_id=subquery.address_id;

此语法不是标准SQL,但是对于这种类型的查询,它比标准SQL更加方便。我相信Oracle(至少)接受类似的东西。


似乎我正在尝试一些不同的东西,例如。如果有3个bool列c1,c2,c3最初都设置为false。但是基于子查询设置为true。更新set c1 = TRUE,其中(subquery1)中的id,set c2 = TRUE,其中id(subquery2)中,set c3 = True,其中id(subquery3)中。当我将其拆分为3个更新时,我很成功,但是我不确定如何通过单个更新获得结果。希望这有道理。
stackover

3
FWIW,Oracle确实接受该基本构造,但是,随着表的增大,更新的性能往往会严重下降。没关系,因为Oracle还支持MERGE语句。
gsiems 2015年

3
这在PostgreSQL 9.5中完全不起作用,我得到了ERROR: 42P01: relation "dummy" does not exist
user9645 16/10/14

72
dummy必须替换为您要更新的表的名称。申请之前,请先了解问题和答案。
安德鲁·拉撒路

1
可能值得一提的是,在查询开始时,不必指定左侧列的路径,而只需在结尾处指定,否则数据库将报错:列引用“ address_id”不明确
OJVM


50

如果使用联接没有性能提升,那么出于可读性考虑,我更喜欢使用通用表表达式(CTE):

WITH subquery AS (
    SELECT address_id, customer, address, partn
    FROM  /* big hairy SQL */ ...
)
UPDATE dummy
SET customer = subquery.customer,
    address  = subquery.address,
    partn    = subquery.partn
FROM subquery
WHERE dummy.address_id = subquery.address_id;

恕我直言有点现代。


1
语法与v9.1之前的Postgres较早版本不兼容(请参阅postgresql.org/docs/9.1/static/sql-update.html和以前的版本)我使用的是v8.2,因此将整个CTE / With语句放在FROM关键字之后的方括号中,它将起作用。
Spcogg第二届

9

有许多更新行的方法。

对于UPDATE使用子查询的行,可以使用这些方法中的任何一种。

  1. 方法1 [使用直接表参考]
UPDATE
  <table1>
SET
  customer=<table2>.customer,
  address=<table2>.address,
  partn=<table2>.partn
FROM
  <table2>
WHERE
  <table1>.address_id=<table2>.address_i;

说明:table1是要更新table2 的表,是要从中获取要替换/更新的值的表。我们正在使用FROM子句,以获取table2的数据。WHERE 子句将有助于设置正确的数据映射。

  1. 方法2 [使用子查询]
UPDATE
  <table1>
SET
  customer=subquery.customer,
  address=subquery.address,
  partn=subquery.partn
FROM
  (
    SELECT
      address_id, customer, address, partn
    FROM  /* big hairy SQL */ ...
  ) AS subquery
WHERE
  dummy.address_id=subquery.address_id;

说明:这里我们在FROM子句中使用子查询,并为其赋予别名。这样它就可以像桌子一样工作。

  1. 方法3 [使用多个联接表]
UPDATE
  <table1>
SET
  customer=<table2>.customer,
  address=<table2>.address,
  partn=<table2>.partn
FROM
  <table2> as t2
  JOIN <table3> as t3
  ON
    t2.id = t3.id
WHERE
  <table1>.address_id=<table2>.address_i;

说明:有时我们遇到这样的情况,表联接对于获取正确的更新数据非常重要。为此,Postgres允许我们在FROM子句中联接多个表。

  1. 方式4 [使用WITH语句]

    • 4.1 [使用简单查询]
WITH subquery AS (
    SELECT
      address_id,
      customer,
      address,
      partn
    FROM
      <table1>;
)
UPDATE <table-X>
SET customer = subquery.customer,
    address  = subquery.address,
    partn    = subquery.partn
FROM subquery
WHERE <table-X>.address_id = subquery.address_id;
  • 4.2 [使用带有复杂JOIN的查询]
WITH subquery AS (
    SELECT address_id, customer, address, partn
    FROM
      <table1> as t1
    JOIN
      <table2> as t2
    ON
      t1.id = t2.id;
    -- You can build as COMPLEX as this query as per your need.
)
UPDATE <table-X>
SET customer = subquery.customer,
    address  = subquery.address,
    partn    = subquery.partn
FROM subquery
WHERE <table-X>.address_id = subquery.address_id;

说明:从Postgres 9.1开始,WITH引入了this()概念。使用它,我们可以进行任何复杂的查询并生成期望的结果。在这里,我们使用这种方法来更新表。

我希望这会有所帮助。😊


1
update json_source_tabcol as d
set isnullable = a.is_Nullable
from information_schema.columns as a 
where a.table_name =d.table_name 
and a.table_schema = d.table_schema 
and a.column_name = d.column_name;

1

@Mayur “ 4.2 [使用具有复杂JOIN的查询]”和“ 公用表表达式(CTE) ”对我来说很有效。

WITH cte AS (
SELECT e.id, e.postcode
FROM employees e
LEFT JOIN locations lc ON lc.postcode=cte.postcode
WHERE e.id=1
)
UPDATE employee_location SET lat=lc.lat, longitude=lc.longi
FROM cte
WHERE employee_location.id=cte.id;

希望这可以帮助...:D

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.