sql >> データベース >  >> RDS >> Oracle

PythonでSQLテーブルを正しく読み取れません:カンマ区切り文字/タプルとしてインポートされたvarchar列

    これは、jaydebeapiを使用するときに問題になるようです jpypeを使用 。これは、Oracleデータベースに接続するときに同じ方法で再現できます(私の場合はOracle 11gR2ですが、ojdbc8.jarを使用しているためです。 、他のバージョンでも発生すると思います。

    これを解決するにはさまざまな方法があります:

    接続を変更する

    エラーはパッケージの特定の組み合わせでのみ発生するように思われるため、最も賢明な方法は、これらを回避してエラーを完全に回避することです。

    1. 代替1:jaydebeapiを使用する jpypeなし

      前述のように、私はjaydebeapiを使用する場合にのみこれを観察します jpypeを使用 。ただし、私の場合、jpype まったく必要ありません。 .jarがあります ファイルをローカルに保存すると、接続がなくても正常に機能します:

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

      私の場合、これは正常に機能し、データフレームを正常に作成します。

    2. 代替2:cx_Oracleを使用する 代わりに:

      cx_Oracleを使用しても、この問題は発生しません。 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()
      

      注:cx_Oracleの場合 動作するには、 Oracle InstantClient が必要です。 インストールされ、適切にセットアップされている(例:Ubuntuのcx_Oracleドキュメント

    事後のデータフレームを修正:

    何らかの理由で上記の代替接続を使用できない場合は、データフレームを変換することもできます。

    1. 代替3:タプルエントリを結合する:

      ''.join()を使用できます タプルを文字列に変換 する 。エントリと列名に対してこれを行う必要があります。

      # 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. 代替4:列のdtypeを変更する:

      dtypeを変更する objectからの影響を受ける列の stringへ 、すべてのエントリも変換されます。これには、たとえば次のような望ましくない副作用がある可能性があることに注意してください。 Noneの変更 文字列の値<N/A> 。また、上記のように、列見出しの名前を個別に変更する必要があります。

      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)
      

    これらはすべて、ほぼ同じdfを生成するはずです。 最後に(dtypesは別として) Noneの可能な置換 値):

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



    1. PostgreSQL 12(windows)にアップデートした後、pg_catalog.pg_settingsからの選択が遅くなりました

    2. ReferentialConstraint の依存プロパティが、ストアで生成された列にマップされている

    3. SQL Serverリストテーブル:すべてのテーブルを表示する方法

    4. Oracle関数から複数の値を返す