Oracle
 sql >> Database >  >> RDS >> Oracle

Impossibile leggere correttamente la tabella SQL in python:colonne varchar importate come caratteri/tuple separati da virgole

Questo sembra essere un problema quando si utilizza jaydebeapi con jpype . Posso riprodurlo quando mi collego a un db Oracle nello stesso modo in cui lo fai (nel mio caso Oracle 11gR2, ma dal momento che stai usando ojdbc8.jar , suppongo che succeda anche con altre versioni).

Esistono diversi modi per risolvere questo problema:

Cambia la tua connessione

Poiché l'errore sembra verificarsi solo in una specifica combinazione di pacchetti, la cosa più sensata da fare è cercare di evitare questi e quindi l'errore del tutto.

  1. Alternativa 1:usa jaydebeapi senza jpype :

    Come notato, lo osservo solo quando utilizzo jaydebeapi con jpype . Tuttavia, nel mio caso, jpype non è affatto necessario. Ho il .jar file localmente e la mia connessione funziona bene senza di esso:

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

    Nel mio caso, funziona bene e crea normalmente i frame di dati.

  2. Alternativa 2:usa cx_Oracle invece:

    Il problema inoltre non si verifica se utilizzo cx_Oracle per connettersi al db Oracle:

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

    Nota:per cx_Oracle per funzionare devi avere il Oracle Instant Client installato e configurato correttamente (vedi ad es. documentazione cx_Oracle per Ubuntu ).

Correggi dataframe dopo il fatto:

Se per qualche motivo non puoi utilizzare le alternative di connessione di cui sopra, puoi anche trasformare il tuo dataframe.

  1. Alternativa 3:unisci le voci della tupla:

    Puoi usare ''.join() per convertire tuple in stringhe . Devi farlo per le voci e i nomi delle colonne.

    # 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. Alternativa 4:cambia dtype di colonne:

    Modificando il dtype di una colonna interessata da object a string , verranno convertite anche tutte le voci. Tieni presente che ciò potrebbe avere effetti collaterali indesiderati, come ad es. modificando None valori alla stringa <N/A> . Inoltre, dovrai rinominare le intestazioni delle colonne separatamente, come sopra.

    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)
    

Tutti questi dovrebbero produrre più o meno lo stesso df alla fine (a parte i dtypes ed eventuale sostituzione di None valori):

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