Oracle
 sql >> Datenbank >  >> RDS >> Oracle

SQL-Tabelle kann in Python nicht richtig gelesen werden:varchar-Spalten, die als kommagetrennte Zeichen / Tupel importiert wurden

Dies scheint ein Problem zu sein, wenn jaydebeapi verwendet wird mit jpype . Ich kann dies reproduzieren, wenn ich eine Verbindung zu einer Oracle-Datenbank auf die gleiche Weise wie Sie herstelle (in meinem Fall Oracle 11gR2, aber da Sie ojdbc8.jar verwenden , ich denke, es passiert auch mit anderen Versionen).

Es gibt verschiedene Möglichkeiten, wie Sie dies lösen können:

Ändern Sie Ihre Verbindung

Da der Fehler scheinbar nur bei einer bestimmten Kombination von Paketen auftritt, ist es am sinnvollsten, diese und damit den Fehler ganz zu vermeiden.

  1. Alternative 1:Verwenden Sie jaydebeapi ohne jpype :

    Wie bereits erwähnt, beobachte ich dies nur bei der Verwendung von jaydebeapi mit jpype . In meinem Fall jedoch jpype wird überhaupt nicht benötigt. Ich habe die .jar Datei lokal und meine Verbindung funktioniert auch ohne sie:

    import jaydebeapi as jdba
    import pandas as pd
    import os
    
    db_host = 'db.host.com'
    db_port = 1521
    db_sid = 'YOURSID'
    
    jar=os.getcwd()+'/ojdbc6.jar'
    
    conn = jdba.connect('oracle.jdbc.driver.OracleDriver', 
                    'jdbc:oracle:thin:@' + db_host + ':' + str(db_port) + ':' + db_sid, 
                    {'user': 'USERNAME', 'password': 'PASSWORD'}, 
                    jar
                    )
    
    df_jay = pd.read_sql('SELECT * FROM YOURSID.table1', conn)
    
    conn.close()
    

    In meinem Fall funktioniert das gut und erstellt die Datenrahmen normal.

  2. Alternative 2:Verwenden Sie cx_Oracle stattdessen:

    Das Problem tritt auch nicht auf, wenn ich cx_Oracle verwende um sich mit der Oracle-Datenbank zu verbinden:

    import cx_Oracle
    import pandas as pd
    import os
    
    db_host = 'db.host.com'
    db_port = 1521
    db_sid = 'YOURSID'
    
    dsn_tns = cx_Oracle.makedsn(db_host, db_port, db_sid)
    cx_conn = cx_Oracle.connect('USERNAME', 'PASSWORD', dsn_tns)
    
    df_cxo = pd.read_sql('SELECT * FROM YOURSID.table1', con=cx_conn)
    
    cx_conn.close()
    

    Hinweis:Für cx_Oracle um zu funktionieren, benötigen Sie den Oracle Instant Client installiert und richtig eingerichtet (siehe z. B. cx_Oracle-Dokumentation für Ubuntu ).

Datenrahmen nachträglich reparieren:

Wenn Sie die obigen Verbindungsalternativen aus irgendeinem Grund nicht verwenden können, können Sie auch Ihren Datenrahmen transformieren.

  1. Alternative 3:Join-Tuple-Einträge:

    Sie können ''.join() verwenden um Tupel in Strings umzuwandeln . Sie müssen dies für die Einträge und die Spaltennamen tun.

    # for all entries that are not None, join the tuples
    for col in df.select_dtypes(include=['object']).columns:
        df[col] = df[col].apply(lambda x: ''.join(x) if x is not None else x)
    
    # also rename the column headings in the same way
    df.rename(columns=lambda x: ''.join(x) if x is not None else x, inplace=True)
    
  2. Alternative 4:Spaltentyp ändern:

    Durch Ändern des dtype einer betroffenen Spalte aus object zu string , werden alle Eingaben ebenfalls konvertiert. Beachten Sie, dass dies unerwünschte Nebenwirkungen haben kann, wie z. Ändern von None -Werte in die Zeichenfolge <N/A> . Außerdem müssen Sie die Spaltenüberschriften wie oben separat umbenennen.

    for col in df.select_dtypes(include=['object']).columns:
        df[col] = df[col].astype('string')
    
    # again, rename headings
    df.rename(columns=lambda x: ''.join(x) if x is not None else x, inplace=True)
    

All dies sollte mehr oder weniger den gleichen df ergeben am Ende (abgesehen von den dtypes und möglicher Ersatz von None Werte):

+---+---------+---------+---------+
|   | COLUMN1 | COLUMN2 | COLUMN3 |
+---+---------+---------+---------+
| 1 | test    | test2   | 1       |
+---+---------+---------+---------+
| 2 | foo     | bar     | 100     |
+---+---------+---------+---------+