2016-07-19 5 views
0

私はOracleデータベースに対してクエリを実行するPythonスクリプトを作成し、その結果をcsvに保存しています。より大きな計画は、別々のアプリケーションで通常の抽出を使用して、ハッシュによるファイルの違いをチェックすることです。Pythonのcx_Oracleとcsvの抽出は異なる実行で別々に保存されました

私が遭遇した問題は、これまでのところ、スクリプトでさまざまな形式の抽出にいくつかのフィールドが保存されていることです。たとえば、1つの抽出に整数を、次の浮動小数点としてフィールドを保存し、日付を2000/01/01に、2000-01-01を別の日付に保存します。

これらの変更は、私の差異チェックスクリプトに合っています。任意のクエリを実行するのに十分な汎用性を維持しながら、すべての抽出が同じ方法で保存されるようにするにはどうすればよいですか?

import sys 
import traceback 
import cx_Oracle 
from Creds import creds 
import csv 
import argparse 
import datetime 

try: 
    conn = cx_Oracle.connect(
     '{username}/{password}@{address}/{dbname}'.format(**creds) 
     ) 
except cx_Oracle.Error as e: 
    print('Unable to connect to database.') 
    print() 
    print(''.join(traceback.format_exception(*sys.exc_info())), file=sys.stderr) 
    sys.exit(1) 


def run_extract(query, out): 
    """ 
    Run the given query and save results to given out path. 

    :param query: Query to be executed. 
    :param out: Path to store results in csv. 
    """ 

    cur = conn.cursor() 

    try: 
     cur.execute(query) 
    except cx_Oracle.DatabaseError as e: 
     print('Unable to run given query.') 
     print() 
     print(query) 
     print() 
     print(''.join(traceback.format_exception(*sys.exc_info())), file=sys.stderr) 
     sys.exit(1) 

    with open(out, 'w', newline='') as out_file: 
     wrt = csv.writer(out_file) 

     header = [] 

     for column in cur.description: 
      header.append(column[0]) 

     wrt.writerow(header) 

     for row in cur: 
      wrt.writerow(row) 

    cur.close() 


def read_sql(file_path): 
    """ 
    Read the SQL from a given filepath and return as a string. 

    :param file_path: File path location of the file to read. 
    """ 

    try: 
     with open(file_path, 'r') as file: 
      return file.read() 
    except FileNotFoundError as e: 
     print('File not found a given path.') 
     print() 
     print(file_path) 
     print() 
     print(''.join(traceback.format_exception(*sys.exc_info())), file=sys.stderr) 
     sys.exit(1) 


def generate_timestamp_path(path): 
    """ 
    Add a timestamp to the beginning of the given path. 

    :param path: File path for the timestamp to be added to. 
    """ 

    if '/' in args.out_file: 
     sep = '/' 
    elif '\\' in args.out_file: 
     sep = '\\' 
    else: 
     sep = '' 

    path = args.out_file.split(sep) 
    stamp = datetime.datetime.now().strftime('%Y%m%dT%H%M%S ') 
    path[-1] = stamp + path[-1] 

    return sep.join(path) 


if __name__ == '__main__': 
    parser = argparse.ArgumentParser() 

    in_group = parser.add_mutually_exclusive_group() 
    in_group.add_argument('-q', '--query', help='String of the query to run.') 
    in_group.add_argument('-f', '--in_file', help='File of the query to run.') 

    parser.add_argument('-o', '--out_file', help='Path to file to store.') 

    parser.add_argument('-t', '--timestamp', 
         help='Store the file with a preceding timestamp.', 
         action='store_true') 

    args = parser.parse_args() 

    if not args.out_file: 
     print('Please provide a path to put the query results with -o.') 
     sys.exit(1) 

    if args.timestamp: 
     path = generate_timestamp_path(args.out_file) 
    else: 
     path = args.out_file 

    if args.query: 
     query = args.query 
    elif args.in_file: 
     query = read_sql(args.in_file) 
    else: 
     print('Please provide either a query string with -q', 
       'or a SQL file with -f.') 
     sys.exit(1) 

    run_extract(query, path) 

答えて

0

コードでは、すべてのデータ型にデフォルトの変換を使用しています。 Oracle型の数値(9)は整数として返されますが、数値自体は浮動小数点数として返されることに注意してください。これをあなたのコントロールの下に置くために、outputtypehandlerを使いたいかもしれません。 :-)そうするための例は、cx_Oracle配布サンプルディレクトリ(ReturnLongsとReturnUnicode)にあります。しかし、Oracleの同じデータ定義は常にPythonで同じ型を返すので、同じ方法で処理したいと思うOracleの異なるデータ型を参照していると思われます。

+0

私の処理では、スクリプトは文字通り、同じクエリを互いに8秒間隔で実行していました。私は出力型ハンドラを調べます。 :-) – user2004245

+0

うーん、好奇心が強い!この動作を示すテストケースが大好きです。あなたが持っている場合は、私に教えてください!ありがとう。 –

関連する問題