Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Não é possível ler corretamente a tabela SQL em python:colunas varchar importadas como caracteres / tuplas separados por vírgula


Isso parece ser um problema ao usar jaydebeapi com jpype . Eu posso reproduzir isso ao conectar a um banco de dados Oracle da mesma maneira que você faz (no meu caso Oracle 11gR2, mas já que você está usando ojdbc8.jar , acho que também acontece com outras versões).

Existem diferentes maneiras de você resolver isso:

Alterar sua conexão


Como o erro parece ocorrer apenas em uma combinação específica de pacotes, a coisa mais sensata a fazer é tentar evitá-los e, portanto, o erro por completo.

  1. Alternativa 1:use jaydebeapi sem jpype :

    Conforme observado, só observo isso ao usar jaydebeapi com jpype . No entanto, no meu caso, jpype não é necessário. Eu tenho o .jar arquivo localmente e minha conexão funciona bem sem ele:
    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()
    

    No meu caso, isso funciona bem e cria os dataframes normalmente.

  2. Alternativa 2:use cx_Oracle em vez disso:

    O problema também não ocorre se eu usar cx_Oracle para se conectar ao banco de dados 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()
    

    Observação:para cx_Oracle para funcionar você precisa ter o Oracle Instant Client instalado e configurado corretamente (consulte, por exemplo, documentação do cx_Oracle para Ubuntu ).

Corrigir dataframe após o fato:


Se, por algum motivo, você não puder usar as alternativas de conexão acima, também poderá transformar seu dataframe.

  1. Alternativa 3:unir entradas de tupla:

    Você pode usar ''.join() para converter tuplas em strings . Você precisa fazer isso para as entradas e os nomes das colunas.
    # 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:altere o tipo de colunas:

    Mudando o dtype de uma coluna afetada de object para string , todas as entradas também serão convertidas. Observe que isso pode ter efeitos colaterais indesejados, como, por exemplo, alterando None valores para a string <N/A> . Além disso, você terá que renomear os títulos das colunas separadamente, como acima.
    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 esses devem produzir mais ou menos o mesmo df no final (além dos dtypes e possível substituição de None valores):
+---+---------+---------+---------+
|   | COLUMN1 | COLUMN2 | COLUMN3 |
+---+---------+---------+---------+
| 1 | test    | test2   | 1       |
+---+---------+---------+---------+
| 2 | foo     | bar     | 100     |
+---+---------+---------+---------+