2012-04-13 11 views
5

में cx_Oracle उपयोग करने के साथ पार्स एसक्यूएल फ़ाइल मैं एक एसक्यूएल फ़ाइल जो मैं पार्स और cx_Oracle अजगर लाइब्रेरी का उपयोग कर ओरेकल में निष्पादित करने के लिए चाहते हैं। एसक्यूएल फ़ाइल में क्लासिक डीएमएल/डीडीएल और पीएल/एसक्यूएल दोनों शामिल हैं, उदाहरण के लिए। इसे इस तरह देख सकते हैं:PL/SQL और DML/DDL अजगर

create.sql:

-- This is some ; malicious comment 
CREATE TABLE FOO(id numeric); 

BEGIN 
    INSERT INTO FOO VALUES(1); 
    INSERT INTO FOO VALUES(2); 
    INSERT INTO FOO VALUES(3); 
END; 
/
CREATE TABLE BAR(id numeric); 

अगर मैं SQLDeveloper या SQL * प्लस में इस फ़ाइल का उपयोग, यह 3 प्रश्नों में विभाजित और निष्पादित किया जाएगा।

हालांकि, cx_Oracle.connect (...)। कर्सर()। निष्पादित (...) एक समय में केवल एक क्वेरी, नहीं एक पूरी फ़ाइल ले सकते हैं। मैं बस string.split(';') (जैसा कि यहां बताया गया है execute a sql script file from cx_oracle?) का उपयोग करके स्ट्रिंग को विभाजित नहीं कर सकता है, क्योंकि दोनों टिप्पणियां विभाजित होंगी (और एक त्रुटि होगी) और पीएल/एसक्यूएल ब्लॉक को एकल कमांड के रूप में निष्पादित नहीं किया जाएगा, इस प्रकार एक त्रुटि हो सकती है।

ओरेकल फ़ोरम (https://forums.oracle.com/forums/thread.jspa?threadID=841025) पर मुझे पता चला है कि cx_Oracle स्वयं पूरी फ़ाइल को पार्स की तरह समर्थन नहीं करता है। मेरा सवाल है - क्या यह मेरे लिए ऐसा करने का एक उपकरण है? उदाहरण के लिए। एक पायथन पुस्तकालय मैं अपनी फाइल को प्रश्नों में विभाजित करने के लिए कह सकता हूं?

संपादित करें: सबसे अच्छे समाधान सीधे SQL * प्लस का उपयोग करना प्रतीत होता है। मैं इस कोड का उपयोग किया है:

# open the file 
f = open(file_path, 'r') 
data = f.read() 
f.close() 

# add EXIT at the end so that SQL*Plus ends (there is no --no-interactive :(
data = "%s\n\nEXIT" % data 

# write result to a temp file (required, SQL*Plus takes a file name argument) 
f = open('tmp.file', 'w') 
f.write(data) 
f.close() 

# execute SQL*Plus 
output = subprocess.check_output(['sqlplus', '%s/%[email protected]%s' % (db_user, db_password, db_address), '@', 'tmp.file']) 

# if an error was found in the result, raise an Exception 
if output.find('ERROR at line') != -1: 
    raise Exception('%s\n\nStack:%s' % ('ERROR found in SQLPlus result', output)) 
+0

। असल में, ओरेकल ब्राइंडेड है और वास्तव में बहु-कथन एसक्यूएल स्क्रिप्ट्स को पार्स करने के लिए * किसी * अंतर्निहित क्षमता में नहीं है, इसलिए एसक्यूएल * प्लस और एसक्यूएल डेवलपर और TOAD सभी अपने * अपने * पार्सर्स को लागू करते हैं :-( –

उत्तर

2

यह एक साथ कई स्टेटमेंट्स को निष्पादित करने के लिए संभव है, लेकिन यह अर्द्ध hacky है। आपको अपने वक्तव्य लपेटने और एक समय में उन्हें निष्पादित करने की आवश्यकता है।

>>> import cx_Oracle 
>>> 
>>> a = cx_Oracle.connect('schema/[email protected]') 
>>> curs = a.cursor() 
>>> SQL = (("""create table tmp_test (a date)"""), 
... ("""insert into tmp_test values (sysdate)""") 
...) 
>>> for i in SQL: 
...  print i 
... 
create table tmp_test (a date) 
insert into tmp_test values (sysdate) 
>>> for i in SQL: 
...  curs.execute(i) 
... 
>>> a.commit() 
>>> 

जैसा कि आपने देखा है कि यह सेमी-कॉलन समस्या को हल नहीं करता है, जिसके लिए कोई आसान जवाब नहीं है। जैसा कि मैंने देखा है कि आपके पास 3 विकल्प हैं:

  1. एक जटिल जटिल पार्सर लिखें, जो मुझे नहीं लगता कि यह एक अच्छा विकल्प है।

  2. अजगर से SQL स्क्रिप्ट निष्पादित न करें; कोड को अलग-अलग SQL स्क्रिप्ट में रखें ताकि पार्सिंग एक अलग पायथन फ़ाइल में, आपके पायथन कोड में एम्बेडेड, डेटाबेस में एक प्रक्रिया में ... आदि हो। यह शायद मेरा पसंदीदा विकल्प है।

  3. उपयोग subprocess और स्क्रिप्ट कि जिस तरह से कहते हैं। यह सबसे सरल और तेज़ विकल्प है लेकिन cx_Oracle का उपयोग नहीं करता है।

    >>> import subprocess 
    >>> cmdline = ['sqlplus','schema/[email protected]','@','tmp_test.sql'] 
    >>> subprocess.call(cmdline) 
    
    SQL*Plus: Release 9.2.0.1.0 - Production on Fri Apr 13 09:40:41 2012 
    
    Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved. 
    
    
    Connected to: 
    Oracle Database 11g Release 11.2.0.1.0 - 64bit Production 
    
    SQL> 
    SQL> CREATE TABLE FOO(id number); 
    
    Table created. 
    
    SQL> 
    SQL> BEGIN 
        2 INSERT INTO FOO VALUES(1); 
        3 INSERT INTO FOO VALUES(2); 
        4 INSERT INTO FOO VALUES(3); 
        5 END; 
        6/
    
    PL/SQL procedure successfully completed. 
    
    SQL> CREATE TABLE BAR(id number); 
    
    Table created. 
    
    SQL> 
    SQL> quit 
    Disconnected from Oracle Database 11g Release 11.2.0.1.0 - 64bit Production 
    0 
    >>> 
    
एक ही समस्या यहाँ
+0

हाय, सबप्रोसेस .call एक उचित समाधान की तरह लगता है (मैं दूसरी पसंद का उपयोग नहीं कर सकता क्योंकि मैं SQL फ़ाइल को नियंत्रित नहीं कर सकता)। हालांकि, जब मैं subplocess के रूप में sqlplus चलाता हूं, तो यह "QUIT" कमांड की प्रतीक्षा करेगा। मेरी पायथन स्क्रिप्ट को होने की आवश्यकता है गैर-इंटरैक्टिव (इस तरह से कई SQL फाइलें निष्पादित की जाएंगी)। आप इसे कैसे बदलेंगे ताकि यह stdin की प्रतीक्षा नहीं करेगा? –

+0

@Savannah, क्या आप एसक्यूएल स्क्रिप्ट पर छोड़ नहीं सकते हैं? जो भी उन्हें उत्पन्न करता है वह होना चाहिए यह सुनिश्चित करना कि वे बाहर निकलें। – Ben

+0

मैं स्क्रिप्ट मैं चलाने के लिए डेटा की तरह कुछ = "% s \ n \ nEXIT"% डेटा जोड़ा है और यह अब काम करता है। –