2016-07-19 4 views
0

Ich arbeite an einem Python-Skript, das Abfragen für eine Oracle-Datenbank ausführt und speichert die Ergebnisse in CSV. Der größere Plan besteht darin, reguläre Extrakte mit einer separaten Anwendung zu verwenden, um Unterschiede in den Dateien durch Hashing zu überprüfen.Python cx_Oracle und CSV-Extrakte mit unterschiedlichen Ausführungen unterschiedlich gespeichert

Das Problem, das ich habe, ist, dass mein Skript bisher einige Felder in den Extrakten in verschiedenen Formaten gespeichert hat. Beispielsweise Speichern eines Felds als Ganzzahl in einem Extrakt und als Float im nächsten und Speichern eines Datums am 2000/01/01 in einem und 2000-01-01 in einem anderen.

Diese Änderungen geben meinem Unterschied Prüfskript eine Passform. Was kann ich tun, um sicherzustellen, dass jeder Extrakt auf die gleiche Weise gespeichert wird, während das Skript generisch genug bleibt, um beliebige Abfragen auszuführen?

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) 

Antwort

0

Ihr Code verwendet einfach die Standardtransformationen für alle Datentypen. Beachten Sie, dass ein Oracle-Typ der Zahl (9) als Integer zurückgegeben wird, die Zahl selbst jedoch als Float zurückgegeben wird. Vielleicht möchten Sie einen Ausgabetyp-Handler verwenden, um dies etwas stärker unter Ihre Kontrolle zu stellen. :-) Beispiele hierfür finden Sie im Verzeichnis cx_Oracle Distribution Samples (ReturnLongs und ReturnUnicode). All das besagt, dass die gleiche Datendefinition in Oracle immer den gleichen Typ in Python zurückgibt - also würde ich vermuten, dass Sie auf verschiedene Datentypen in Oracle verweisen, die Sie auf die gleiche Weise bearbeiten möchten.

+0

In meiner Verarbeitung für diese Zeit lief das Skript buchstäblich die gleiche Abfrage 8 Sekunden voneinander getrennt. Ich werde die Ausgabetyphandler nachschlagen. :-) – user2004245

+0

Hmm, neugierig! Ich würde gerne einen Testfall haben, der dieses Verhalten demonstriert. Wenn Sie einen haben, lassen Sie es mich bitte wissen! Vielen Dank. –

Verwandte Themen