การอัพเดตแถวของตารางใน postgres โดยใช้แบบสอบถามย่อย


303

ใช้ 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

ใช่ฉันทำ แต่มันสร้างระบบ
stackover

คำตอบ:


683

ช่วยให้ 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 คอลัมน์บูล c1, c2, c3 ทั้งหมดตั้งค่าเป็นเท็จเริ่มแรก แต่ขึ้นอยู่กับแบบสอบถามย่อยที่ถูกตั้งค่าเป็นจริง update set c1 = TRUE โดยที่ id ใน (subquery1), set c2 = TRUE โดยที่ id in (subquery2), set c3 = True ที่ id ใน (subquery3) ฉันประสบความสำเร็จเมื่อฉันแบ่งการอัปเดตนี้เป็น 3 ครั้ง แต่ฉันไม่แน่ใจว่าจะได้ผลลัพธ์อย่างไรด้วยการอัปเดตครั้งเดียว หวังว่านี่จะสมเหตุสมผล
stackover

3
FWIW, Oracle ยอมรับการสร้างพื้นฐานอย่างไรก็ตามประสิทธิภาพของการอัปเดตมีแนวโน้มที่จะลดลงอย่างรุนแรงเนื่องจากตารางมีขนาดใหญ่ขึ้น ไม่เป็นไรแม้ว่า Oracle จะรองรับคำสั่ง MERGE เช่นกัน
gsiems

3
ทั้งหมดนี้ใช้ไม่ได้กับ postgresql 9.5 ฉันได้รับERROR: 42P01: relation "dummy" does not exist
user9645

73
dummyจะต้องถูกแทนที่ด้วยชื่อของตารางที่คุณพยายามอัปเดต โปรดเข้าใจคำถามและคำตอบก่อนลองสมัคร
Andrew Lazarus

1
มันอาจจะคุ้มค่าที่จะกล่าวถึงว่าในการเริ่มต้นของแบบสอบถามไม่จำเป็นต้องระบุเส้นทางไปยังคอลัมน์ของด้านซ้ายเฉพาะที่สิ้นสุดมิฉะนั้น db จะบ่นกับข้อผิดพลาด: อ้างอิงคอลัมน์ "address_id" ไม่ชัดเจน
OJVM

126

คุณอยู่หลังUPDATE FROMไวยากรณ์

UPDATE 
  table T1  
SET 
  column1 = T2.column1 
FROM 
  table T2 
  INNER JOIN table T3 USING (column2) 
WHERE 
  T1.column2 = T2.column2;

อ้างอิง


2
ควรเป็นคำตอบที่เลือก
Joshua Kifer

51

หากไม่มีประสิทธิภาพเพิ่มขึ้นโดยใช้การเข้าร่วมฉันชอบ Common Table Expressions (CTEs) สำหรับการอ่าน:

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;

IMHO ทันสมัยกว่านิดหน่อย


1
ไวยากรณ์ไม่สามารถใช้งานร่วมกับ Postgres เวอร์ชันเก่ากว่าก่อน v9.1 (ดูpostgresql.org/docs/9.1/static/sql-update.htmlและรุ่นก่อนหน้า) ฉันใช้ v8.2 แล้วคุณจึงมี เพื่อวางทั้งคำสั่ง CTE / With ไว้ในวงเล็บหลังคำสำคัญจาก FROM และจะใช้งานได้
Spcogg ที่สอง

9

มีหลายวิธีในการอัปเดตแถว

เมื่อพูดถึงUPDATEแถวโดยใช้คิวรีย่อยคุณสามารถใช้วิธีการใดก็ได้เหล่านี้

  1. Approach-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. Approach-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;

คำอธิบาย: ที่นี่เราใช้ subquerie ภายในFROMประโยคและให้นามแฝงกับมัน เพื่อให้มันทำหน้าที่เหมือนโต๊ะ

  1. Approach-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. Approach-4 [ใช้กับข้อความสั่ง]

    • 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 [การใช้แบบสอบถามด้วยการรวมที่ซับซ้อน]
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แนวคิด( ) นี้ได้ถูกนำเสนอ การใช้สิ่งนั้นเราสามารถสร้างแบบสอบถามที่ซับซ้อนและสร้างผลลัพธ์ที่ต้องการได้ ที่นี่เราใช้วิธีนี้เพื่ออัปเดตตาราง

ฉันหวังว่านี่จะเป็นประโยชน์😊


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 [การใช้คิวรีที่มีการรวมที่ซับซ้อน]"กับCommon Table Expressions (CTEs)ได้หลอกลวงสำหรับฉัน

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.