दिलचस्प पोस्ट
Android में मेरी गतिविधि से रिंगटोन कैसे सेट करें? स्टार्टअप पर मैं अपना ऐप कैसे प्रारंभ करूं? jqgrid लंबा पाठ लपेटन क्लाइंट साइड पर एचटीएमएल को सैनिटेज़ / रिइरेट करें एक कुंजी को छोड़कर एक जेएस वस्तु क्लोन करें X = X ++ के बीच अंतर क्या है; बनाम एक्स ++ ;? "तत्काल" और "आरंभ" के बीच क्या अंतर है? जावा स्ट्रिंग को sql.Timestamp में कनवर्ट करें Dummies के लिए जावास्क्रिप्ट getters और setters? PHP चेतावनी: foreach के लिए अमान्य तर्क प्रदान किया गया () किस संकलक पर मुझे विश्वास होना चाहिए? क्या मैं एक्सएएमएल (पूर्व .नेट 4 फ्रेमवर्क) में एक सामान्य प्रकार निर्दिष्ट कर सकता हूं? जेन्गो मॉडल ऑब्जेक्ट को सभी क्षेत्रों के साथ अक्षांश में परिवर्तित करें == ऑपरेटर का प्रयोग करके फ़्लोट / डबल वैल्यू की तुलना करना मैक ओएस एक्स पर पायथन 3 के लिए पीईपी कैसे स्थापित करें?

PostgreSQL में डुप्लिकेट अपडेट पर डालें?

कई महीनों पहले मैंने स्टैक ओवरफ्लो पर एक उत्तर से सीखा है कि एक बार में निम्न सिंटैक्स का उपयोग करके एक बार में एकाधिक अपडेट कैसे करें I

INSERT INTO table (id, field, field2) VALUES (1, A, X), (2, B, Y), (3, C, Z) ON DUPLICATE KEY UPDATE field=VALUES(Col1), field2=VALUES(Col2); 

अब मैं PostgreSQL पर स्विच कर लिया है और जाहिरा तौर पर यह सही नहीं है। यह सभी सही तालिकाओं का उल्लेख कर रहा है, इसलिए मुझे लगता है कि यह अलग-अलग कीवर्ड का उपयोग किया जा रहा है लेकिन मुझे यकीन नहीं है कि पोस्टग्रेएसक्यूएल दस्तावेज़ में कहां शामिल है।

स्पष्ट करने के लिए, मैं कई चीजों को सम्मिलित करना चाहता हूं और यदि वे पहले से ही उन्हें अपडेट करने के लिए मौजूद हैं।

Solutions Collecting From Web of "PostgreSQL में डुप्लिकेट अपडेट पर डालें?"

PostgreSQL संस्करण 9.5 के बाद से यूपीएसईआरटी वाक्यविन्यास है, साथ में कॉन्फ्लिक्ट क्लॉज के साथ। निम्न सिंटैक्स के साथ (MySQL के समान)

 INSERT INTO the_table (id, column_1, column_2) VALUES (1, 'A', 'X'), (2, 'B', 'Y'), (3, 'C', 'Z') ON CONFLICT (id) DO UPDATE SET column_1 = excluded.column_1, column_2 = excluded.column_2; 

"अपसर्ट" के लिए पोस्टग्रेस्क्ल के ईमेल समूह अभिलेखागार की खोज से मैन्युअल रूप से, जो आप संभवतः करना चाहते हैं, उसका एक उदाहरण ढूंढने की ओर जाता है:

उदाहरण 38-2 अद्यतन / INSERT के साथ अपवाद

इस उदाहरण में अपवाद या तो अद्यतन या INSERT को निष्पादित करने के लिए उपयोग किया जाता है, जैसा उपयुक्त है:

 CREATE TABLE db (a INT PRIMARY KEY, b TEXT); CREATE FUNCTION merge_db(key INT, data TEXT) RETURNS VOID AS $$ BEGIN LOOP -- first try to update the key -- note that "a" must be unique UPDATE db SET b = data WHERE a = key; IF found THEN RETURN; END IF; -- not there, so try to insert the key -- if someone else inserts the same key concurrently, -- we could get a unique-key failure BEGIN INSERT INTO db(a,b) VALUES (key, data); RETURN; EXCEPTION WHEN unique_violation THEN -- do nothing, and loop to try the UPDATE again END; END LOOP; END; $$ LANGUAGE plpgsql; SELECT merge_db(1, 'david'); SELECT merge_db(1, 'dennis'); 

हैकर्स की मेलिंग सूची में 9.1 और इसके बाद के संस्करण में सीटीई का उपयोग करते हुए यह संभवतः थोक में कैसे करना है इसका एक उदाहरण है:

 WITH foos AS (SELECT (UNNEST(%foo[])).*) updated as (UPDATE foo SET foo.a = foos.a ... RETURNING foo.id) INSERT INTO foo SELECT foos.* FROM foos LEFT JOIN updated USING(id) WHERE updated.id IS NULL; 

एक स्पष्ट उदाहरण के लिए a_horse_with_no_name के उत्तर देखें।

चेतावनी: एक ही समय में कई सत्रों से निष्पादित होने पर यह सुरक्षित नहीं है (नीचे चेतावनियां देखें)।


Postgresql में "यूपीएसईआर" करने का एक और चतुर तरीका दो अनुक्रमिक अद्यतन / इनसेट स्टेटमेंट करना है जो प्रत्येक सफल होने के लिए डिज़ाइन किए गए हैं या कोई प्रभाव नहीं है।

 UPDATE table SET field='C', field2='Z' WHERE id=3; INSERT INTO table (id, field, field2) SELECT 3, 'C', 'Z' WHERE NOT EXISTS (SELECT 1 FROM table WHERE id=3); 

"आईडी = 3" के साथ एक पंक्ति पहले से मौजूद है, तो यह अद्यतन सफल होगा, अन्यथा इसका कोई प्रभाव नहीं होगा

INSERT केवल तब सफल होगा जब "id = 3" के साथ पंक्ति पहले से मौजूद नहीं है।

आप इन दोनों को एक स्ट्रिंग में जोड़ सकते हैं और उन्हें अपने ऐप से एक एकल एसक्यूएल स्टेटमेंट के साथ चला सकते हैं। एक लेनदेन में उन्हें एक साथ चलाना अत्यधिक अनुशंसित है।

यह अलगाव में या लॉक किए गए टेबल पर चलाए जाने पर बहुत अच्छी तरह से काम करता है, लेकिन दौड़ शर्तों के अधीन है, इसका मतलब यह है कि डुप्लिकेट कुंजी त्रुटि के साथ असफल हो सकता है यदि एक पंक्ति को एक साथ जोड़ दिया गया हो, या जब पंक्ति को समवर्ती रूप से हटा दिया गया हो, । PostgreSQL 9.1 या उच्चतर पर एक SERIALIZABLE लेनदेन एक बहुत ही उच्च सीरिजलाइजेशन विफलता दर की लागत पर मज़बूती से इसे संभालना होगा, जिसका अर्थ है कि आपको बहुत कुछ पुन: प्रयास करना होगा। देखें कि इतनी जटिल क्यों बढ़ जाती है , जो इस मामले की अधिक विस्तृत जानकारी पर चर्चा करता है।

यह दृष्टिकोण read committed अलगाव में खोए अद्यतनों के अधीन भी है, जब तक कि एप्लिकेशन प्रभावित पंक्ति गणनाओं की जांच नहीं करता और पुष्टि करता है कि या तो insert या update एक पंक्ति को प्रभावित करता है ।

PostgreSQL 9.1 के साथ यह एक लेखन योग्य सीटीई ( सामान्य तालिका अभिव्यक्ति ) का उपयोग करके प्राप्त किया जा सकता है:

 WITH new_values (id, field1, field2) as ( values (1, 'A', 'X'), (2, 'B', 'Y'), (3, 'C', 'Z') ), upsert as ( update mytable m set field1 = nv.field1, field2 = nv.field2 FROM new_values nv WHERE m.id = nv.id RETURNING m.* ) INSERT INTO mytable (id, field1, field2) SELECT id, field1, field2 FROM new_values WHERE NOT EXISTS (SELECT 1 FROM upsert up WHERE up.id = new_values.id) 

इन ब्लॉग प्रविष्टियों को देखें:

  • लिखने योग्य सीटीई के माध्यम से अपसेट
  • 9.1 के लिए प्रतीक्षा कर रहा है – लेखन योग्य सीटीई
  • यूपीएसईटी इतनी कम क्यों है?

ध्यान दें कि यह समाधान एक अनन्य कुंजी उल्लंघन को नहीं रोकता है, लेकिन यह खोए हुए अद्यतनों के लिए कमजोर नहीं है।
क्रेग रिंगर द्वारा dba.stackexchange.com पर अनुसरण करें देखें

PostgreSQL 9.5 और नए में आप INSERT ... ON CONFLICT UPDATE उपयोग कर सकते हैं INSERT ... ON CONFLICT UPDATE

दस्तावेज़ीकरण देखें।

एक MySQL INSERT ... ON DUPLICATE KEY UPDATE सीधे एक ON CONFLICT UPDATE करने के लिए rephrased किया जा सकता है। न तो SQL- मानक सिंटैक्स है, वे दोनों डेटाबेस-विशिष्ट एक्सटेंशन हैं इसके लिए अच्छे कारणों का इस्तेमाल नहीं किया गया है , एक नया सिंटैक्स सिर्फ मज़े के लिए नहीं बनाया गया था (MySQL के वाक्यविन्यास के पास भी ऐसे मुद्दों हैं जिसका अर्थ यह सीधे अपनाया नहीं गया था)।

जैसे कि दिए गए सेटअप:

 CREATE TABLE tablename (a integer primary key, b integer, c integer); INSERT INTO tablename (a, b, c) values (1, 2, 3); 

MySQL क्वेरी:

 INSERT INTO tablename (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1; 

हो जाता है:

 INSERT INTO tablename (a, b, c) values (1, 2, 10) ON CONFLICT (a) DO UPDATE SET c = tablename.c + 1; 

अंतर:

  • विशिष्टता जांच के लिए उपयोग करने के लिए आपको स्तंभ नाम (या अद्वितीय बाध्यता नाम) निर्दिष्ट करना होगा यह ON CONFLICT (columnname) DO

  • कीवर्ड SET का इस्तेमाल किया जाना चाहिए, जैसे कि यह एक सामान्य UPDATE स्टेटमेंट था

इसमें कुछ अच्छी सुविधाएं भी हैं:

  • आपके UPDATE पर एक WHERE क्लॉज हो सकता है (आपको प्रभावी रूप से निश्चित मानों के लिए ON CONFLICT IGNORE ON CONFLICT UPDATE ON CONFLICT IGNORE करना)

  • प्रस्तावित-के-सम्मिलन मान पंक्ति-चर EXCLUDED रूप में उपलब्ध हैं, जो कि लक्ष्य तालिका के समान संरचना है। तालिका नाम का उपयोग करके आप तालिका में मूल मान प्राप्त कर सकते हैं। तो इस मामले में EXCLUDED.c 10 हो जाएगा (क्योंकि हमने जो डालने की कोशिश की थी) और "table".c 3 होगी क्योंकि यह तालिका में वर्तमान मान है। आप SET एक्सप्रेशंस में या दोनों का उपयोग कर सकते हैं और WHERE क्लॉज

अप्सर्ट पर बैकग्राउंड के लिए कैसे पोस्टगेसएसक्यूएल में यूपीएसईआरटी (मिर्ज, इन्सर्ट … डुप्लिकेट अपडेट पर) को कैसे देखें ?

मैं एक ही चीज़ की तलाश कर रहा था जब मैं यहां आया था, लेकिन एक सामान्य "अपसर्ट" समारोह की कमी मुझे थोड़ा परेशान करती थी, इसलिए मैंने सोचा था कि आप अपडेट को पास कर सकते हैं और एसक्यूएल को उस फ़ंक्शन पर मैन्युअल रूप से तर्क के रूप में जोड़ सकते हैं

यह ऐसा दिखेगा:

 CREATE FUNCTION upsert (sql_update TEXT, sql_insert TEXT) RETURNS VOID LANGUAGE plpgsql AS $$ BEGIN LOOP -- first try to update EXECUTE sql_update; -- check if the row is found IF FOUND THEN RETURN; END IF; -- not found so insert the row BEGIN EXECUTE sql_insert; RETURN; EXCEPTION WHEN unique_violation THEN -- do nothing and loop END; END LOOP; END; $$; 

और शायद आप जो करना शुरू में करना चाहते थे, बैच "अपसर्ट", आप एससीएल का इस्तेमाल कर सकते हैं, ताकि आप को sql_update विभाजित किया जा सके और अलग-अलग अद्यतनों को पाश कर सकें। http://archives.postgresql.org/pgsql- प्रदर्शन / 2006-04 / msg00557.php

उच्चतम लागत आपके कोड से क्वेरी निष्पादित कर रही है, डेटाबेस पक्ष पर निष्पादन लागत बहुत छोटी है

ऐसा करने के लिए कोई आसान आदेश नहीं है

सबसे सही तरीका फ़ंक्शन का उपयोग करना है, जैसे डॉक्स से एक है।

एक अन्य समाधान (हालांकि सुरक्षित नहीं है) लौटने के साथ अपडेट करना है, जांचें कि कौन सी पंक्तियाँ अपडेट थीं, और बाकी सब को डालें

की तर्ज पर कुछ:

 update table set column = x.column from (values (1,'aa'),(2,'bb'),(3,'cc')) as x (id, column) where table.id = x.id returning id; 

आईडी मानते हुए: 2 लौटा था:

 insert into table (id, column) values (1, 'aa'), (3, 'cc'); 

बेशक यह जल्दी या बाद में (समवर्ती वातावरण में) जमानत होगी, क्योंकि यहां स्पष्ट दौड़ की स्थिति है, लेकिन आम तौर पर यह काम करेगा।

यहाँ विषय पर एक लंबा और अधिक व्यापक लेख है ।

निजी तौर पर, मैंने एक "नियम" को सम्मिलन वक्तव्य से जुड़ा है। कहते हैं कि आपके पास एक "डीएनएस" तालिका थी, जो प्रत्येक ग्राहक प्रति दिन के आधार पर डीएनएस दर्ज करती है:

 CREATE TABLE dns ( "time" timestamp without time zone NOT NULL, customer_id integer NOT NULL, hits integer ); 

आप नवीनीकृत मूल्यों के साथ पंक्तियों को फिर से सम्मिलित करने में सक्षम होना चाहते थे या उन्हें पहले से मौजूद नहीं होने पर उन्हें बनाना चाहते थे Customer_id और समय पर keyed कुछ इस तरह:

 CREATE RULE replace_dns AS ON INSERT TO dns WHERE (EXISTS (SELECT 1 FROM dns WHERE ((dns."time" = new."time") AND (dns.customer_id = new.customer_id)))) DO INSTEAD UPDATE dns SET hits = new.hits WHERE ((dns."time" = new."time") AND (dns.customer_id = new.customer_id)); 

अद्यतन: यदि एक साथ आवेषण हो रहा है, तो यह असफल होने की संभावना है, क्योंकि यह अनूठे_इओलेशन अपवाद उत्पन्न करेगा। हालांकि, गैर-समाप्त लेन-देन जारी रहेगा और सफल होगा, और आपको समाप्त लेनदेन दोहराने की आवश्यकता है

हालांकि, यदि हर समय होने वाले सम्मिलित होने के कई टन होते हैं, तो आप सम्मिलित बयानों के आसपास एक टेबल लॉक रखना चाहते हैं: साझा करें पंक्ति अनन्य लॉकिंग आपके लक्ष्य तालिका में पंक्तियों को सम्मिलित, हटा या अपडेट करने वाले किसी भी परिचालन को रोक देगा। हालांकि, अद्यतन जो अद्वितीय कुंजी को अद्यतन नहीं करते सुरक्षित हैं, इसलिए यदि आप कोई कार्रवाई नहीं करेंगे, तो इसके बजाय सलाहकार ताले का उपयोग करें

साथ ही, कॉप्पी कमांड नियमों का उपयोग नहीं करता है, इसलिए यदि आप कॉपी के साथ सम्मिलित कर रहे हैं तो आपको इसके बजाय ट्रिगर का उपयोग करने की आवश्यकता होगी।

मैं उपरोक्त कस्टम "अपसर्ट" फ़ंक्शन, यदि आप लिखना और बदलना चाहते हैं:

`

  CREATE OR REPLACE FUNCTION upsert(sql_insert text, sql_update text) RETURNS void AS $BODY$ BEGIN -- first try to insert and after to update. Note : insert has pk and update not... EXECUTE sql_insert; RETURN; EXCEPTION WHEN unique_violation THEN EXECUTE sql_update; IF FOUND THEN RETURN; END IF; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100; ALTER FUNCTION upsert(text, text) OWNER TO postgres;` 

और निष्पादित करने के बाद, ऐसा कुछ करें:

 SELECT upsert($$INSERT INTO ...$$,$$UPDATE... $$) 

कंपाइलर त्रुटियों से बचने के लिए डबल डॉलर-कॉमा को डालना महत्वपूर्ण है

  • गति की जांच करें …

खाता वैल्यू युग्ज के रूप में खाता सेटिंग्स को प्रबंधित करने के लिए मेरे पास एक समान समस्या है डिज़ाइन मानदंड यह है कि अलग-अलग क्लाइंट में अलग-अलग सेटिंग सेट हो सकते हैं।

मेरा समाधान, जेडब्ल्यूपी के समान, अपने आवेदन के भीतर मर्ज रिकॉर्ड का निर्माण करने के लिए थोक मिटाना और बदलना है।

यह बहुत बुलेटप्रूफ, प्लेटफ़ॉर्म स्वतंत्र है और चूंकि ग्राहक प्रति ग्राहक लगभग 20 से अधिक सेटिंग्स नहीं हैं, यह केवल 3 काफी कम लोड डीबी कॉल है – शायद सबसे तेज़ तरीका

अलग-अलग पंक्तियों को अपडेट करने का विकल्प – अपवादों की जांच करने के बाद – या कुछ संयोजन में घृणित कोड धीमा होता है और अक्सर टूट जाता है क्योंकि (जैसा कि ऊपर वर्णित है) गैर मानक एसक्यूएल अपवाद हैंडलिंग डीबी से डीबी बदल रहा है या फिर रिलीज़ करने के लिए जारी भी है।

  #This is pseudo-code - within the application: BEGIN TRANSACTION - get transaction lock SELECT all current name value pairs where id = $id into a hash record create a merge record from the current and update record (set intersection where shared keys in new win, and empty values in new are deleted). DELETE all name value pairs where id = $id COPY/INSERT merged records END TRANSACTION 

सर्वाधिक पसंद किए गए उत्तर के समान, लेकिन थोड़ा तेज काम करता है:

 WITH upsert AS (UPDATE spider_count SET tally=1 WHERE date='today' RETURNING *) INSERT INTO spider_count (spider, tally) SELECT 'Googlebot', 1 WHERE NOT EXISTS (SELECT * FROM upsert) 

(स्रोत: http://www.the-art-of-web.com/sql/upsert/ )

 CREATE OR REPLACE FUNCTION save_user(_id integer, _name character varying) RETURNS boolean AS $BODY$ BEGIN UPDATE users SET name = _name WHERE id = _id; IF FOUND THEN RETURN true; END IF; BEGIN INSERT INTO users (id, name) VALUES (_id, _name); EXCEPTION WHEN OTHERS THEN UPDATE users SET name = _name WHERE id = _id; END; RETURN TRUE; END; $BODY$ LANGUAGE plpgsql VOLATILE STRICT 

अद्यतन संशोधित पंक्तियों की संख्या वापस कर देगा। यदि आप जेडीबीसी (जावा) का उपयोग करते हैं, तो आप 0 के मुकाबले इस मान की जांच कर सकते हैं, और यदि कोई पंक्तियों को प्रभावित नहीं किया गया है, तो इसके बजाय INSERT आग लगाना। यदि आप कुछ अन्य प्रोग्रामिंग भाषा का उपयोग करते हैं, तो संशोधित पंक्तियों की संख्या अभी भी प्राप्त की जा सकती है, दस्तावेज़ीकरण की जांच करें।

यह शानदार नहीं हो सकता है लेकिन आपके पास बहुत आसान एसक्यूएल है जो कॉलिंग कोड से उपयोग करने के लिए अधिक तुच्छ है। अलग-अलग, यदि आप पीएल / पीएसक्यूएल में दस लाइन स्क्रिप्ट लिखते हैं, तो आपको शायद इसके लिए एक या अन्य प्रकार की यूनिट टेस्ट मिलनी चाहिए।

मैं इस समारोह मर्ज का उपयोग करें

 CREATE OR REPLACE FUNCTION merge_tabla(key INT, data TEXT) RETURNS void AS $BODY$ BEGIN IF EXISTS(SELECT a FROM tabla WHERE a = key) THEN UPDATE tabla SET b = data WHERE a = key; RETURN; ELSE INSERT INTO tabla(a,b) VALUES (key, data); RETURN; END IF; END; $BODY$ LANGUAGE plpgsql 

INSERT स्टेटमेंट के पोस्टग्रेएसक्यूएल दस्तावेज के अनुसार, ON DUPLICATE KEY केस को संभालने का समर्थन नहीं है। सिंटैक्स का यह हिस्सा एक स्वामित्व वाली MySQL एक्सटेंशन है।

संपादित करें: यह अपेक्षा के अनुरूप काम नहीं करता है स्वीकृत उत्तर के विपरीत, यह अद्वितीय कुंजी उल्लंघन पैदा करता है जब दो प्रक्रिया बार-बार upsert_foo एक साथ कॉल करते हैं।

यूरेका! मुझे एक क्वेरी में ऐसा करने का एक तरीका पता चला है: UPDATE ... RETURNING उपयोग UPDATE ... RETURNING लिए कि कोई भी पंक्तियों को प्रभावित किया गया था:

 CREATE TABLE foo (k INT PRIMARY KEY, v TEXT); CREATE FUNCTION update_foo(k INT, v TEXT) RETURNS SETOF INT AS $$ UPDATE foo SET v = $2 WHERE k = $1 RETURNING $1 $$ LANGUAGE sql; CREATE FUNCTION upsert_foo(k INT, v TEXT) RETURNS VOID AS $$ INSERT INTO foo SELECT $1, $2 WHERE NOT EXISTS (SELECT update_foo($1, $2)) $$ LANGUAGE sql; 

UPDATE को एक अलग प्रक्रिया में करना चाहिए क्योंकि दुर्भाग्यवश, यह एक वाक्य रचना त्रुटि है:

 ... WHERE NOT EXISTS (UPDATE ...) 

अब यह वांछित के रूप में काम करता है:

 SELECT upsert_foo(1, 'hi'); SELECT upsert_foo(1, 'bye'); SELECT upsert_foo(3, 'hi'); SELECT upsert_foo(3, 'bye'); 

छोटे सेट मर्ज करने के लिए, उपर्युक्त कार्य का उपयोग करना ठीक है। हालांकि, अगर आप बड़ी मात्रा में डेटा मर्ज कर रहे हैं, तो मैं http://mbk.projects.postgresql.org देखकर सुझाव देता हूं

वर्तमान सर्वश्रेष्ठ अभ्यास जिसे मैं जानता हूं:

  1. ताज़ा तालिका में नया / अपडेट किया हुआ डेटा कॉपी करें (सुनिश्चित करें, या यदि आप लागत ठीक है तो आप इनसर्ट कर सकते हैं)
  2. अधिग्रहण लॉक [वैकल्पिक] (सलाहकार तालिका ताले के लिए बेहतर है, आईएमओ)
  3. मर्ज करें। (मज़ा भाग)