PostgreSQL में एक अद्यतन + शामिल कैसे करें?


508

मूल रूप से, मैं यह करना चाहता हूं:

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

मुझे पूरा यकीन है कि यह MySQL (मेरी पृष्ठभूमि) में काम करेगा, लेकिन यह पोस्टग्रेज में काम नहीं करता है। मुझे जो त्रुटि मिलती है वह है:

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

निश्चित रूप से ऐसा करने का एक आसान तरीका है, लेकिन मुझे उचित वाक्यविन्यास नहीं मिल रहा है। तो, मैं इसे PostgreSQL में कैसे लिखूंगा?


5
पोस्टग्रैज सिंटैक्स अलग है: postgresql.org/docs/8.1/static/sql-update.html
मार्क बी

4
वाहन_वचन, शिपमेंट_शिपमेंट? यह एक दिलचस्प तालिका नामकरण सम्मेलन है
CodeAndCats

3
@CodeAndCats Haha ... यह अजीब लगता है ना? मुझे लगता है कि मैं उस समय Django का उपयोग कर रहा था, और टेबल सुविधा द्वारा समूहीकृत हैं। तो वहाँ एक दृश्य vehicles_*तालिकाओं, और कुछ shipments_*तालिकाओं होता।
मपेन

जवाबों:


776

अद्यतन वाक्य रचना है:

[[RECURSIVE] with_query [, ...]] के साथ
अद्यतन [केवल] तालिका [[एएस] उर्फ]
    सेट {कॉलम = {एक्सप्रेशन | DEFAULT} |
          (कॉलम [, ...]) = ({व्यंजक | DEFAULT} [, ...])} [, ...]
    [F_ from_list]
    [जहां हालत | जहां कर्सर_नाम का नियम]
    [रिटर्निग * | 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 

यदि अद्यतन तालिका की संपूर्ण सूची पर निर्भर करता है, तो क्या उन्हें अद्यतन अनुभाग या FROM अनुभाग में होना चाहिए?
ted.strauss

11
@ ted.strauss: FROM में तालिकाओं की एक सूची हो सकती है।
मार्क बायर्स

140

मैं अपने उदाहरण से थोड़ा और समझाता हूं।

कार्य: सही जानकारी, जहाँ अभिवावकों (माध्यमिक विद्यालय छोड़ने के बारे में छात्रों) ने पहले विश्वविद्यालय को आवेदन प्रस्तुत किए हैं, जबकि उन्हें स्कूल प्रमाण पत्र मिला है (हाँ, उन्हें पहले प्रमाण पत्र मिला था, जबकि वे जारी किए गए प्रमाण पत्र द्वारा निर्दिष्ट किए गए थे)। सर्टिफिकेट इश्यू डेट को फिट करने के लिए आवेदन जमा की तारीख बढ़ाएं।

इस प्रकार। अगले 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

आप देख सकते हैं, मूल सबक्वेरी JOINके ONखंड में से एक बन गए हैं WHEREकी स्थिति है, जिसके द्वारा conjucted है ANDदूसरों है, जो सबक्वेरी से बिना किसी परिवर्तन के ले जाया गया है के साथ। और JOINखुद के साथ तालिका करने की कोई आवश्यकता नहीं है (जैसा कि यह उपश्रेणी में था)।


16
आप तीसरी तालिका में कैसे शामिल होंगे?
ग्रेटर

19
आप JOINइसे हमेशा की तरह FROMसूची में शामिल करते हैं :FROM abiturients b JOIN addresses c ON c.abiturient_id = b.id
Envek

@Envek - आप जॉयस अलास का उपयोग नहीं कर सकते, मैंने अभी-अभी जाँच की है। postgresql.org/docs/10/static/sql-update.html
एड्रियन स्मिथ

3
@ AdrianSmith, आप JOIN को UPDATE में उपयोग नहीं कर सकते, लेकिन इसे UPDATE के from_listक्लॉज (जो कि PostgreSQL का SQL का विस्तार है) में उपयोग कर सकते हैं । इसके अलावा, आपके द्वारा दिए गए लिंक पर टेबल कैविएट में शामिल होने के बारे में नोट्स देखें।
Envek

@Envek - आह, स्पष्टीकरण के लिए धन्यवाद, मैंने याद किया।
एड्रियन स्मिथ

130

मार्क बायर्स का उत्तर इस स्थिति में इष्टतम है। हालांकि अधिक जटिल स्थितियों में आप उन चुनिंदा क्वेरी को ले सकते हैं जो राऊड और परिकलित मान लौटाते हैं और इसे इस तरह अद्यतन क्वेरी में संलग्न करते हैं:

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 table1
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 स्तंभ नामों की अस्पष्टता के बारे में शिकायत करेगा।


1
मुझे वास्तव में यह पसंद है क्योंकि मैं हमेशा अपने "चयन" को शीर्ष पर ले जाने और "अपडेट" के साथ इसे बदलने के साथ एक नर्वस नर्वस हूं, विशेष रूप से कई जॉइन के साथ। यह बड़े पैमाने पर अद्यतन करने से पहले मुझे एसक्यूएल डंप की संख्या को कम करना चाहिए। :)
dannysauer 19

5
निश्चित रूप से क्यों नहीं, लेकिन इस क्वेरी का सीटीई संस्करण "सादा
जुड़ाव

इस समाधान का अन्य लाभ दो से अधिक तालिकाओं से जुड़ने की क्षमता है जो आपके अंतिम गणना मूल्य के साथ कई चयनों के साथ या अंतिम विवरण का उपयोग करके प्राप्त कर सकते हैं।
एलेक्स मुरो

1
यह कमाल का है। मैंने अपना चयन तैयार किया था और @dannysauer की तरह, मैं रूपांतरण से डर गया था। यह बस यह मेरे लिए करता है। उत्तम!
शीतदंश

1
आपके पहले SQL उदाहरण में एक सिंटैक्स त्रुटि है। "अपडेट टी 1" टी उपसमुदाय से उपनाम का उपयोग नहीं कर सकता है, इसे तालिका नाम: "अपडेट टेबल 1" का उपयोग करने की आवश्यकता है। आप इसे अपने दूसरे उदाहरण में सही ढंग से करते हैं।
एरिकस नोव

79

उन लोगों के लिए जो 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" तालिका से समझा जाता है।


4
इसे ध्यान में रखते हुए (और उप के साथ अंदर नहीं) में एक वास्तविक जुड़ाव के साथ पहला उत्तर है, यह वास्तविक स्वीकृत उत्तर होना चाहिए। या तो यह या इस सवाल का नाम भ्रम से बचने के लिए बदला जाना चाहिए कि क्या पोस्टग्रैसेकल अपडेट में जुड़ने का समर्थन करता है या नहीं।
नेकलेस

यह काम करता हैं। लेकिन एक हैक की तरह लगता है
एम। हबीब

यह ध्यान दिया जाना चाहिए कि प्रलेखन ( postgresql.org/docs/11/sql-update.html ) के अनुसार , क्लॉज से लक्ष्य तालिका को सूचीबद्ध करने से लक्ष्य तालिका स्व-जुड़ जाएगी। कम आत्मविश्वास से, यह मुझे भी प्रतीत होता है कि यह एक क्रॉस-सेल्फ-ज्वाइन है, जिसके अनपेक्षित परिणाम और / या अन्य निहितार्थ हो सकते हैं।
बेन कॉलिन्स

13

एक 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
--the below line is critical for updating ONLY joined rows
AND a.pk_id = a_alias.pk_id;

यह ऊपर उल्लेख किया गया था, लेकिन केवल एक टिप्पणी के माध्यम से। फिर भी यह महत्वपूर्ण है कि नए परिणाम पोस्ट करने वाले सही परिणाम प्राप्त करने के लिए महत्वपूर्ण है


7

ये रहा:

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

सरल के रूप में मैं यह कर सकता है। धन्यवाद दोस्तों!

यह भी कर सकते हैं:

-- Doesn't work apparently
update vehicles_vehicle 
set price=s.price_per_vehicle
from vehicles_vehicle v
join shipments_shipment s on v.shipment_id=s.id;

लेकिन फिर आपको वाहन तालिका दो बार मिल गई है, और आपको केवल एक बार इसे बदलने की अनुमति है, और आप "सेट" भाग में उपनाम का उपयोग नहीं कर सकते।


@littlegreen क्या आप इसके बारे में निश्चित हैं? क्या joinयह अड़चन नहीं है?
एमपीएन

4
@ मैं पुष्टि कर सकता हूं कि यह सभी रिकॉर्ड्स को एक मूल्य पर अपडेट करता है। यह वह नहीं करता जो आप उम्मीद करेंगे।
एडम बेल

1

यहाँ एक साधारण एसक्यूएल है जो नाम से मिडिलनेम क्षेत्र का उपयोग करके Name3 टेबल पर Mid_Name को अपडेट करता है:

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

0

नीचे दिए गए लिंक में एक उदाहरण है जो हल करता है और बेहतर तरीके से समझने में मदद करता है कि कैसे उपयोग करें updateऔर joinपोस्टग्रेज के साथ।

UPDATE product
SET net_price = price - price * discount
FROM
product_segment
WHERE
product.segment_id = product_segment.id;

देखें: http://www.postgresqltutorial.com/postgresql-update-join/


0

पहली तालिका का नाम: tbl_table1 (tab1)। दूसरी तालिका का नाम: tbl_table2 (tab2)।

"INACTIVE" tbl_table1 के ac_status कॉलम को सेट करें

update common.tbl_table1 as tab1
set ac_status= 'INACTIVE' --tbl_table1's "ac_status"
from common.tbl_table2 as tab2
where tab1.ref_id= '1111111' 
and tab2.rel_type= 'CUSTOMER';
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.