Rainbow Planet (GT×IT×SP×SA)

IT技術を分かりやすく簡潔にまとめることによる学習の効率化、また日常の気付きを記録に残すことを目指します。

01_IT技術 (Technology)

PythonのSQLAlchemyで「ArgumentError : Could not parse rfc1738 URL」エラーや「InvalidRequestError: Could not reflect: requested tables(s)」エラーが出た時の対処について

投稿日:2020年3月15日 更新日:

(0)目次&概説

(1) エラー対応1:sqlalchemy.exc.ArgumentError
 (1-1) 発生状況・エラーメッセージ
  (1-1-1) エラーメッセージ
  (1-1-2) エラーとなったソース
 (1-2) 原因
 (1-3) 対処方法
(2) エラー2:Could not reflect: requested table(s)
 (2-1) 発生状況・エラーメッセージ
  (2-1-1) エラーメッセージ
  (2-1-2) エラーとなったソース
 (2-2) 原因
 (2-3) 対処方法

(1) エラー対応1:sqlalchemy.exc.ArgumentError

(1-1) 発生状況・エラーメッセージ

Web上で公開されているcsvデータのURLに対して「requests」パッケージの「get」関数を用いてデータを取得し、それをPandasの「read_csv」関数でDataframeに入れてから「to_sql」関数でOracleDBのテーブルにINSERTしようとした際にこのエラーに遭遇しました。

(1-1-1) エラーメッセージ
sqlalchemy.exc.ArgumentError: Could not parse rfc1738 URL from string '[Table name]'

 

(1-1-2) エラーとなったソース
import datapackage
import cx_Oracle
import sqlalchemy
import pandas as pd
import requests
from io import StringIO

def main():
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36'}
    url = 'https://[your URL].json'
    dp = datapackage.Package(url)
    res = dp.resources

    from sqlalchemy import create_engine
    engine = create_engine('oracle://[your schema]:[your password]@[hostname]:[port]/[sid]')
    for res in res:
        if res.tabular:
            if res.descriptor['datahub']['type'] == 'derived/csv':
                s=requests.get(res.descriptor['path'], headers= headers).text
                df = pd.read_csv(StringIO(s))
                print(res.descriptor['path'])
                df.to_sql(engine,'CMTB_COMPANY_MASTER',if_exists='replace',index=False)

if __name__ == '__main__':
    main()

(図101)

目次にもどる

(1-2) 原因

引数の順番が正しく指定されていなかったためでした。「to_sql」関数は暗黙の「self」を除いた場合の第1引数は「SQLのテーブル名」で第2引数が”create_engine”関数の実行結果(sqlalchemy.engine.base.Engine)ですが、上記の例ではこれが逆になっているためにエラーとなっています。
(※本来はEngineインスタンス(「Engine(oracle://[your schema]:***@[hostname]:[port]/orcl)」のような文字列)を想定していた所、テーブル名を誤って引数として与えたため)

参考:Pandasの「to_sql」の説明
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html

目次にもどる

(1-3) 対処方法

上記の第1引数”engine”と第2引数の”CMTB_COMPANY_MASTER”の順番を逆にしたら、当該エラーは起こらなくなりました。
(ただし、今度は後述の別のエラーに遭遇しますが・・)

df.to_sql('CMTB_COMPANY_MASTER',engine,if_exists='replace',index=False)

目次にもどる

(2) エラー2:Could not reflect: requested table(s)

(2-1) 発生状況・エラーメッセージ

(2-1-1) エラーメッセージ
sqlalchemy.exc.InvalidRequestError: Could not reflect: requested table(s) not available in Engine(oracle://[your schema]:***@[hostname]:[port]/orcl): ([your table name])

 

(2-1-2) エラーとなったソース

前の章からの主な差分箇所は以下です。
①SQLAlchemyの”create_engine”でEngineオブジェクトを作りDB接続しています。
②上記のEngineオブジェクトを用いてPandasの「to_sql」でDBのテーブルにレコードをINSERTしています。

import datapackage
import cx_Oracle
import sqlalchemy
import pandas as pd
import requests
from io import StringIO

def main():
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36'}
    url = 'https://[your URL].json'
    dp = datapackage.Package(url)
    res = dp.resources

    from sqlalchemy import create_engine
    engine = create_engine('oracle://[your schema]:[password]@[hostname]:[port]/[sid]')
    for res in res:
        if res.tabular:
            if res.descriptor['datahub']['type'] == 'derived/csv':
                s=requests.get(res.descriptor['path'], headers= headers).text
                df = pd.read_csv(StringIO(s))
                print(res.descriptor['path'])
                df.to_sql('CMTB_COMPANY_MASTER',engine,if_exists='replace',index=False)

if __name__ == '__main__':
    main()

(図201)

目次にもどる

(2-2) 原因

「引数のテーブル名」と「DB側のテーブル名」がマッチしていない事が原因でした。どうやらDB側ではテーブル名を小文字に変換しているため、引数で大文字のテーブル名を与えると不一致でエラーとなるようです。実際に警告としてもその旨の文章が出ており「Consider using lower case table names」と小文字を推奨する記載も見受けられます。

C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python37_64\lib\site-packages\pandas\io\sql.py:1336: UserWarning: The provided table name 'CMTB_COMPANY_MASTER' is not found exactly as such in the database after writing the table, possibly due to case sensitivity issues. Consider using lower case table names.
  warnings.warn(msg, UserWarning)

目次にもどる

(2-3) 対処方法

テーブル名をstr型の変数に代入して「.lower()」メソッドで小文字変換することでミスマッチを防止できます。
■修正前:

df.to_sql('CMTB_COMPANY_MASTER',engine,if_exists='replace',index=False)

■修正後:

tab_name = 'CMTB_COMPANY_MASTER'
df.to_sql(tab_name.lower(),engine,if_exists='replace',index=False)

(図202)
・エラーは解消


・テーブルにも正常にレコードが格納されている

目次にもどる

Adsense審査用広告コード


Adsense審査用広告コード


-01_IT技術 (Technology)

執筆者:


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

OracleDBのメディア障害やインスタンス障害からの復旧について

(0)目次&概説 (1) 障害復旧について  (1-1) インスタンス障害  (1-2) メディア障害   (1-2-1) 制御ファイル   (1-2-2) REDOログファイル   (1-2-3) …

VBAで処理と処理の間に一定時間を空けて実行する方法

今回はVBAで処理と処理の間に一定時間を空けて実行する方法について、備忘も兼ねて記載します。 (0)目次&概説 (1) Application.wait (2) サンプルプログラムソース (3) サン …

VBAによるマトリクスの行列を反転させて転記するプログラム

(0)目次&概説 (1) マクロ概要 (2) 使用方法 (3) アルゴリズム概要 (4) プログラム (1) マクロ概要 マトリクス形式で表現されたデータの行と列を入れ替えるプログラムです。 (※Ex …

Windows Server2012で仮想サーバーのメモリ割当ての変更をする手順

(0)目次&概説 (1) 前提条件 (2) メモリ割当ての変更手順  (2-1) 事前作業(ログ取得)  (2-2) 仮想サーバーの停止  (2-3) リソース変更  (2-4) 仮想サーバーの起動 …

PythonでSQLAlchemyを使ってOracleDBに接続する方法

(0)目次&概説 (1) 記事の目的  (1-1) 目的  (1-2) 前提条件 (2) 事前準備  (2-1) 準備1(cx_oracleパッケージの導入)   (2-1-1) インストール資源の入 …

Top