sql >> Base de Datos >  >> RDS >> Oracle

No se puede leer correctamente la tabla SQL en python:columnas varchar importadas como caracteres/tuplas separados por comas

Esto parece ser un problema cuando se usa jaydebeapi con jpype . Puedo reproducir esto cuando me conecto a una base de datos Oracle de la misma manera que lo haces tú (en mi caso, Oracle 11gR2, pero como estás usando ojdbc8.jar , supongo que también pasa con otras versiones).

Hay diferentes formas de resolver esto:

Cambia tu conexión

Dado que el error solo parece ocurrir en una combinación específica de paquetes, lo más sensato es tratar de evitarlos y, por lo tanto, el error por completo.

  1. Alternativa 1:Usar jaydebeapi sin jpype :

    Como se señaló, solo observo esto cuando uso jaydebeapi con jpype . Sin embargo, en mi caso, jpype no es necesario en absoluto. Tengo el .jar archivo localmente y mi conexión funciona bien sin él:

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

    En mi caso, esto funciona bien y crea los marcos de datos normalmente.

  2. Alternativa 2:Usar cx_Oracle en cambio:

    El problema tampoco ocurre si uso cx_Oracle para conectarse a la base de datos de 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:para cx_Oracle para trabajar tienes que tener el Oracle Instant Client instalado y configurado correctamente (consulte, por ejemplo, cx_Documentación de Oracle para Ubuntu ).

Corregir marco de datos después del hecho:

Si por algún motivo no puede utilizar las alternativas de conexión anteriores, también puede transformar su marco de datos.

  1. Alternativa 3:unir entradas de tupla:

    Puedes usar ''.join() para convertir tuplas en cadenas . Debe hacer esto para las entradas y los nombres de las columnas.

    # 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:cambiar el tipo de columnas:

    Cambiando el dtype de una columna afectada de object a string , todas las entradas también se convertirán. Tenga en cuenta que esto puede tener efectos secundarios no deseados, como p. cambiando None valores a la cadena <N/A> . Además, tendrá que cambiar el nombre de los encabezados de las columnas por separado, como se indicó anteriormente.

    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)
    

Todos estos deberían producir más o menos el mismo df al final (aparte de los dtypes y posible reemplazo de None valores):

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