2010-03-03 16 views
8

के बाद एक लेनदेन जारी रखना मैं लॉग फ़ाइल से डेटाबेस में रिकॉर्ड्स का एक बड़ा सम्मिलन कर रहा हूं। कभी-कभी (प्रत्येक हज़ार में से 1 पंक्ति) पंक्तियों में से एक प्राथमिक कुंजी का उल्लंघन करती है और लेनदेन विफल होने का कारण बनती है। वर्तमान में, उपयोगकर्ता को मैन्युअल रूप से उस फ़ाइल से गुजरना है जो विफलता का कारण बनता है और पुन: आयात करने का प्रयास करने से पहले अपमानजनक पंक्ति को हटा देता है। यह देखते हुए कि आयात करने के लिए सैकड़ों फाइलें अव्यवहारिक हैं।प्राथमिक कुंजी उल्लंघन त्रुटि

मेरा प्रश्न: मैं रिकॉर्ड कि प्राथमिक कुंजी बाधा का उल्लंघन होगा की प्रविष्टि कैसे छोड़ सकते हैं, प्रत्येक पंक्ति से पहले एक SELECT बयान करने के लिए अगर यह पहले से मौजूद है को देखने के लिए बिना?

नोट: मैं बहुत समान प्रश्न #1054695 के बारे में पता कर रहा हूँ, लेकिन यह एक एसक्यूएल सर्वर विशिष्ट जवाब प्रतीत होता है और मैं PostgreSQL उपयोग कर रहा हूँ (अजगर/psycopg2 के माध्यम से आयात करना)।

उत्तर

12

आप लेनदेन में SAVEPOINT का भी उपयोग कर सकते हैं।

database.execute("BEGIN") 
foreach data_row in input_data_dictionary: 
    database.execute("SAVEPOINT bulk_savepoint") 
    try: 
     database.execute("INSERT", table, data_row) 
    except: 
     database.execute("ROLLBACK TO SAVEPOINT bulk_savepoint") 
     log_error(data_row) 
     error_count = error_count + 1 
    else: 
     database.execute("RELEASE SAVEPOINT bulk_savepoint") 

if error_count > error_threshold: 
    database.execute("ROLLBACK") 
else: 
    database.execute("COMMIT") 

संपादित करें:: यहाँ दस्तावेज में उदाहरण के एक मामूली बदलाव के आधार पर psql में कार्रवाई में इस का एक वास्तविक उदाहरण (एसक्यूएल लगाया जाता बयान "है>

Pythonish स्यूडोकोड आवेदन की ओर से उदाहरण देकर स्पष्ट करना है "):

> CREATE TABLE table1 (test_field INTEGER NOT NULL PRIMARY KEY); 
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "table1_pkey" for table "table1" 
CREATE TABLE 

> BEGIN; 
BEGIN 
> INSERT INTO table1 VALUES (1); 
INSERT 0 1 
> SAVEPOINT my_savepoint; 
SAVEPOINT 
> INSERT INTO table1 VALUES (1); 
ERROR: duplicate key value violates unique constraint "table1_pkey" 
> ROLLBACK TO SAVEPOINT my_savepoint; 
ROLLBACK 
> INSERT INTO table1 VALUES (3); 
INSERT 0 1 
> COMMIT; 
COMMIT 
> SELECT * FROM table1; 
test_field 
------------ 
      1 
      3 
(2 rows) 

ध्यान दें कि त्रुटि 3 त्रुटि के बाद डाला गया था, लेकिन फिर भी उसी लेनदेन के अंदर!

SAVEPOINT के लिए प्रलेखन http://www.postgresql.org/docs/8.4/static/sql-savepoint.html पर है।

name = uuid.uuid1().hex 
cr.execute('SAVEPOINT "%s"' % name) 
try: 
    # your failing query goes here 
except Exception: 
    cr.execute('ROLLBACK TO SAVEPOINT "%s"' % name) 
    # your alternative code goes here 
else: 
    cr.execute('RELEASE SAVEPOINT "%s"' % name) 

इस कोड को मान लिया गया लेन-देन वहाँ चल रहा है, अन्यथा:

+0

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

+0

हां यह होगा। यह SAVEPOINT का पूरा बिंदु है। मैंने एक ठोस उदाहरण देने के लिए अपना जवाब संपादित कर लिया है। –

+1

---- संपादित करें ---- क्षमा करें, मैं गलत था ... मुझ पर शर्म की बात है;) यह ठीक काम करता है, आप सही हैं। –

4

मैं आपके अद्वितीय उल्लंघनों पर अपवादों को पकड़ने के लिए संग्रहीत प्रक्रिया का उपयोग करूंगा। उदाहरण:

CREATE OR REPLACE FUNCTION my_insert(i_foo text, i_bar text) 
    RETURNS boolean LANGUAGE plpgsql AS 
$BODY$ 
begin 
    insert into foo(x, y) values(i_foo, i_bar); 
    exception 
     when unique_violation THEN -- nothing 

    return true; 
end; 
$BODY$; 

SELECT my_insert('value 1','another value'); 
+0

बिल्कुल सही, धन्यवाद। – John

+0

अपने अपवादों को लॉग करना हमेशा बेहतर होता है .. आप इसे लॉग इन करने के लिए अपवाद ब्लॉग को संशोधित कर सकते हैं और अभी भी जारी रख सकते हैं। – Guru

+0

आप फ़ंक्शन को अपवादों को लॉग इन करने दे सकते हैं, कोई समस्या नहीं। –

0

या आप एसएसआईएस का उपयोग कर सकते हैं और असफल पंक्तियां सफल लोगों की तुलना में एक अलग रास्ता लेती हैं।

जब से तुम usinga differnt डेटाबेस हैं आप एक मचान मेज पर फ़ाइलें सम्मिलित प्रकार भारी मात्रा में कर सकते हैं और उसके बाद ही उन रिकॉर्ड है जो एक exisitng आईडी नहीं है का चयन करने के लिए SQL कोड का उपयोग करें?

+0

क्या आप एसएसआईएस द्वारा अपना मतलब बता सकते हैं? – John

+0

एसएसआईएस डाटा आयात उपकरण है जो SQL सर्वर के साथ आता है। मैंने नहीं पकड़ा कि आप पोस्टग्रे का उपयोग कर रहे हैं। यह पोस्टग्रे के लिए अभी भी काम कर सकता है लेकिन मुझे यकीन नहीं है कि आप इसे कैसे प्राप्त करेंगे क्योंकि मुझे नहीं लगता कि यह SQL सर्वर के मुफ़्त संस्करण के साथ आता है। – HLGEM

1

आप लेन-देन करने के लिए एक rollback या सिर्फ कोड है कि अपवाद (करोड़ कर्सर है) को जन्म देती है पहले एक को बचाने के मुद्दे पर एक रोलबैक कर सकते हैं आपको वह त्रुटि संदेश प्राप्त नहीं होगा।

Django postgresql बैकएंड creates cursors सीधे psycopg से। शायद भविष्य में वे Django कर्सर के लिए प्रॉक्सी क्लास बनाते हैं, cursor of odoo के समान। वे following code साथ कर्सर का विस्तार (आत्म कर्सर है):

@contextmanager 
@check 
def savepoint(self): 
    """context manager entering in a new savepoint""" 
    name = uuid.uuid1().hex 
    self.execute('SAVEPOINT "%s"' % name) 
    try: 
     yield 
    except Exception: 
     self.execute('ROLLBACK TO SAVEPOINT "%s"' % name) 
     raise 
    else: 
     self.execute('RELEASE SAVEPOINT "%s"' % name) 

इस तरह संदर्भ अपने कोड आसान बनाता है, यह हो जाएगा:

try: 
    with cr.savepoint(): 
     # your failing query goes here 
except Exception: 
    # your alternative code goes here 

और कोड अधिक पठनीय है, क्योंकि लेनदेन सामान नहीं है।

संबंधित मुद्दे