2012-04-13 17 views
5

Tôi có một tệp SQL mà tôi muốn phân tích cú pháp và thực hiện trong oracle bằng cách sử dụng thư viện python cx_Oracle. Tệp SQL chứa cả DML/DDL và PL/SQL cổ điển, ví dụ: nó có thể trông như thế này:Phân tích tệp SQL bằng PL/SQL và DML/DDL bằng cách sử dụng cx_Oracle trong python

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); 

nếu tôi sử dụng tập tin này trong SQLDeveloper hoặc SQL * Plus, nó sẽ được chia thành 3 truy vấn và thực hiện.

Tuy nhiên, cx_Oracle.connect (...). Cursor(). Execute (...) chỉ có thể thực hiện MỘT truy vấn tại một thời điểm, không phải toàn bộ tệp. Tôi không thể đơn giản tách chuỗi bằng cách sử dụng string.split(';') (như được đề xuất ở đây execute a sql script file from cx_oracle?), vì cả nhận xét sẽ được tách ra (và sẽ gây ra lỗi) và khối PL/SQL sẽ không được thực hiện dưới dạng lệnh đơn, do đó gây ra lỗi.

Trên diễn đàn Oracle (https://forums.oracle.com/forums/thread.jspa?threadID=841025) Tôi đã tìm thấy rằng chính cx_Oracle không hỗ trợ những thứ như phân tích cú pháp toàn bộ tệp. Câu hỏi của tôi là - có một công cụ để làm điều này cho tôi không? Ví dụ. một thư viện python tôi có thể gọi để chia tập tin của tôi thành các truy vấn?

Chỉnh sửa: Các giải pháp tốt nhất dường như sử dụng SQL * Plus trực tiếp. Tôi đã sử dụng mã này:

# 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

Cùng một vấn đề ở đây. Về cơ bản, Oracle là braindead và không thực sự có khả năng * tích hợp sẵn để phân tích cú pháp các kịch bản lệnh SQL nhiều câu lệnh, vì vậy SQL * Plus và SQL Developer và TOAD thực hiện tất cả các trình phân tích cú pháp * riêng của họ :-( –

Trả lời

2

Có thể thực hiện nhiều câu lệnh cùng một lúc nhưng lại bán thành công. Bạn cần phải quấn các câu lệnh của bạn và thực thi chúng từng lần một.

>>> 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() 
>>> 

Như bạn đã lưu ý, điều này không giải quyết được vấn đề nửa tràng, mà không có câu trả lời dễ dàng. Như tôi thấy, bạn có 3 tùy chọn:

  1. Viết một trình phân tích cú pháp quá phức tạp mà tôi không nghĩ là một lựa chọn tốt.

  2. Không thực thi các tập lệnh SQL từ Python; có mã trong các tập lệnh SQL riêng biệt để phân tích cú pháp dễ dàng, trong một tệp Python riêng biệt, được nhúng trong mã Python của bạn, trong quy trình trong cơ sở dữ liệu ... v.v. Đây có lẽ là tùy chọn ưa thích của tôi.

  3. Sử dụng subprocess và gọi tập lệnh theo cách đó. Đây là tùy chọn đơn giản và nhanh nhất nhưng hoàn toàn không sử dụng 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

Xin chào, tiến trình con .call có vẻ như là một giải pháp hợp lý (tôi không thể sử dụng lựa chọn thứ hai vì tôi không thể kiểm soát tệp SQL) .Tuy nhiên, khi tôi chạy sqlplus làm subprocess, nó sẽ đợi lệnh "QUIT". không tương tác (sẽ có một số tập tin SQL được thực hiện theo cách này) .Bạn sẽ thay đổi nó như thế nào để nó không chờ đợi stdin? –

+0

@Savannah, bạn có thể không thêm phần thoát vào tập lệnh SQL không? – Ben

+0

Tôi đã thêm một cái gì đó như dữ liệu = "% s \ n \ nEXIT"% dữ liệu vào tập lệnh mà tôi chạy và nó hoạt động ngay bây giờ –

Các vấn đề liên quan