Oracle
 sql >> Base de données >  >> RDS >> Oracle

Impossible de lire correctement la table SQL en python :les colonnes varchar sont importées sous forme de caractères/tuples séparés par des virgules

Cela semble être un problème lors de l'utilisation de jaydebeapi avec jpype . Je peux reproduire cela lors de la connexion à une base de données Oracle de la même manière que vous (dans mon cas Oracle 11gR2, mais puisque vous utilisez ojdbc8.jar , je suppose que cela arrive aussi avec d'autres versions).

Vous pouvez résoudre ce problème de différentes manières :

Modifier votre connexion

Étant donné que l'erreur ne semble se produire que dans une combinaison spécifique de packages, la chose la plus sensée à faire est d'essayer d'éviter ceux-ci et donc l'erreur.

  1. Alternative 1 :Utiliser jaydebeapi sans jpype :

    Comme indiqué, je n'observe cela que lors de l'utilisation de jaydebeapi avec jpype . Cependant, dans mon cas, jpype n'est pas du tout nécessaire. J'ai le .jar fichier local et ma connexion fonctionne bien sans :

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

    Dans mon cas, cela fonctionne bien et crée les dataframes normalement.

  2. Alternative 2 :Utiliser cx_Oracle à la place :

    Le problème ne se produit pas non plus si j'utilise cx_Oracle pour se connecter à la base de données 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()
    

    Remarque :Pour cx_Oracle pour travailler, vous devez avoir le Oracle Instant Client installé et correctement configuré (voir par exemple documentation cx_Oracle pour Ubuntu ).

Corrigez la trame de données après coup :

Si pour une raison quelconque, vous ne pouvez pas utiliser les alternatives de connexion ci-dessus, vous pouvez également transformer votre dataframe.

  1. Alternative 3 :joindre les entrées de tuple :

    Vous pouvez utiliser ''.join() pour convertir les tuples en chaînes . Vous devez le faire pour les entrées et les noms de 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. Alternative 4 :modifier le type de colonnes :

    En changeant le dtype d'une colonne affectée de object à string , toutes les entrées seront également converties. Notez que cela peut avoir des effets secondaires indésirables, comme par ex. changer None valeurs à la chaîne <N/A> . De plus, vous devrez renommer les en-têtes de colonne séparément, comme ci-dessus.

    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)
    

Tous ces éléments devraient donner plus ou moins le même df au final (à part les dtypes et remplacement éventuel de None valeurs):

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