質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.30%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

2103閲覧

pythonのSQLAlchemyによる接続コネクションがうまくいかない

python_heroku

総合スコア23

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2024/07/30 15:41

編集2024/08/01 10:56

実現したいこと

EOLに伴いpythonを3.8.0から3.12.0にversion upしたい
そのversion upに伴い各種モジュールもupdateしたい

問題事象

元々下記のversionでは実施できていたSQLAlchemyのcreate_eningeでMS SQLに対してコネクション生成し、to_sqlでのデータ挿入処理が、version up後は上手くできない

元々のversion
python:ver3.8.0
pandas:1.1.3
SQLAlchemy:1.4.22

OS:Debian buster
Server DB:v17.3

ケース1

SQLAlchemyで作成したcreate_engineコネクションを利用したto_sqlによるDBへのデータ挿入処理においてエラーが発生する
python:ver3.12.0
pandas:2.2.2
SQLAlchemy:1.4.22

OS:Debian buster
Server DB:v17.3

・警告内容

UserWarning : pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.

・エラー内容

'Engine' object has no attribute 'cursor'

ケース2

SQLAlchemyで作成したcreate_engineコネクションを利用したto_sqlによるDBへのデータ挿入処理自体は出来るが、トランザクション処理ができない
python:ver3.12.0
pandas:2.1.4
SQLAlchemy:1.4.36

OS:Debian buster
Server DB:v17.3

・警告内容

UserWarning : pandas only supports SQLAlchemy connectable (engine/connection) or database string URI or sqlite DBAPI2 connection. Other DBAPI2 objects are not tested. Please consider using SQLAlchemy.

・エラー内容

'Connection' object has no attribute 'commit'

該当のソースコード(元々)

python

1import pandas as pd 2from sqlalchemy import create_engine 3engine = create_engine(接続情報) 4 5df = pd.DataFrame() 6tablename= 'test' 7 8try: 9 # 下記のコネクション微妙に違うかも。。 10 df.to_sql(tablename, engine.raw_connection().engine, if_exists="append") 11 12except Exception as ex: 13 engine.raw_connection().rollback() 14

該当のソースコード(ケース1)

python

1import pandas as pd 2from sqlalchemy import create_engine 3engine = create_engine(接続情報) 4 5df = pd.DataFrame() 6tablename= 'test' 7 8df.to_sql(tablename, engine)

該当のソースコード(ケース2)

python

1import pandas as pd 2from sqlalchemy import create_engine 3engine = create_engine(接続情報) 4 5df = pd.DataFrame() 6tablename= 'test' 7 8try: 9 with engine.begin() as conn: 10 df.to_sql(tablename, engine, if_exists="append") 11 12 conn.commit() 13 14except Exception as ex: 15 conn.rollback()

試したこと

pandas2.2以上において、SQLAlchemyが2.0以上じゃないと対応していない、というような記事を見つけたので、2.1.4にダウングレードしたらトランザクション処理なしであれば警告はできるが正常系では問題なし。ただし、トランザクション処理のやり方がわからない

逆にSQLAlchemyを2.0以上にすると今度はcreate_engineが作成できない。やり方が変わっているように見受けるが、その方法がわからない。

手打ちでコードやエラーなど記載しているので、若干のtypoあるかもだが、元々は動いていたので、create_engineで入力している情報間違いではない想定。警告も元々はなし。
おそらくversionの互換性の問題だと思っている。

教えて頂きたい事

  1. pandasは2.0以上、SQLAlchemyは特にこだわりなしなので、どのようなバージョンでどのようなソースとすればトランザクション処理含めて動作するのか知りたい

  2. 警告においてcreate_engineが作成できてないようなエラーが発生しているが、DB自体にアクセスはできているように見受けたので、この警告が出る理由は何なのか?どのようにしたらこの警告を解消できるのか?

その他

情報に不足あればご指摘下さい

頂いた回答に対しての追記

create_engineの方法間違っている?と思いまして、該当部分の記述追加します。元々のversionではうまくいったので、これが現在のバージョンだとダメなのか?などが頂いた情報を参考に試してもみたのですが、引き続き同事象が継続していました。

python

1engine = create_engine( 2 "mssql+pyodbc://{user_id}:{password}@{localhost}:{port}/{dbname}?driver={driver}".format( 3 localhost = "略", 4 port = "略", 5 dbname = "略", 6 userid = "略", 7 password = "略", 8 driver = "ODBC Driver 17 for SQL Server", 9)

with句のインデントの指摘を頂いて、確かになと思ったので、下記も試してみたのですが、同様のエラーが生じました

python

1with engine.begin() as conn: 2 try: 3 df.to_sql(tablename, engine, if_exists="append") 4 5 conn.commit() 6 7 except Exception as ex: 8 conn.rollback()
'Connection' object has no attribute 'commit'

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

FiroProchainezo

2024/08/01 01:12

``` with engine.begin() as conn: df.to_sql(tablename, engine) conn.commit() ``` この部分インデント合ってますか?
python_heroku

2024/08/01 06:22

コメントありがとうございます。 指摘いただき、 with engine.begin() as conn: df.to_sql(tablename, engine) conn.commit() こちらも試してみたのですが、同エラーが発生しておりました。
FiroProchainezo

2024/08/01 07:05

コメント欄はインデントが保持されないので、ここにコードを書かれてもわからないです。 私のコメントは、 `with xxx as conn:`から`conn.commit()`部分のインデントが正しいかを確認しています。 `with`で開いたあと、`conn.commit()`実行前に`conn`が閉じていますが、意図した通りですか? コードの転記ミス(質問作成にあたり手打ちしてたりしませんか?)がありませんか? つまり、「インデントの位置は合ってますか?」という指摘です。 connection閉じてしまっているから、commitできないのような気がします。 > mssql*pyodbc: URIのこの部分、`*`じゃなくて`+`じゃないですか? 何かを参考にしたんでしょうか? エラーメッセージ見る限り、pandasがサポートしているURIになっていないように見えます。
退会済みユーザー

退会済みユーザー

2024/08/01 08:47

全然関係ありませんが、コメントでもブラウザによっては(確認した限りだとfirefoxでは)コピペするとインデントが分かったりしますよ。chromeでもconsoleで console.log(document.querySelector('div.questionCommentListItem_comment__ZlKzZ').textContent); とか console.log(document.querySelector('div.questionCommentListItem_innerpanel__Zlq9W').textContent) とかしたら見えます。裏技的な方法ですが…。 ただソースで修正した方がいいですね。 あとはdriverとdatabaseのバージョンの違いが書かれていないし、何より、どこまで何が出来ているのかの確認が出来ていません。そしてOSも明記しないといけません。 odbcで繋げるだけならSQLエディタでも出来るのでそこからなのか、それが出来たならpyodbcからなのか、それが出来たらSQLAlchemyなのか、それが出来たなら初めてpandasやpython自身の話になります。 全部まとめて上げておいて、出来ませんでした〜、それを他人に丸投げで聞いていては話になりません。 他人に聞くのであれば再現環境構築用のスクリプトを書き、誰でも全ケース再現できるようにしてから質問しましょう。 その手間が惜しいのであれば、どんなに時間がかかったとしても、自分で調べた方が早いのです。 有料のサポートを受ければ簡単な問答と詳細データ提示だけで調べてくれる場合もありますよ。 ただ今回のように再現環境の記述すらまともに出来ないのであれば、有料サポートでも解決できないかもしれません。
python_heroku

2024/08/01 10:31

FireProchainezo様 コメント欄にインデントが保存されない件、失礼しました。 おっしゃる通り、そこ自体おかしいのでは?というのはありましたので、おそらく指摘事項の内容で修正してみて試してみましたが、同様のエラーが生じているように見受けました。 質問内容編集しております。そちらであれば試したインデントの形もご確認いただけるかと。 またcreate_engineについてもご指摘事項について誤記でしたので修正しております。
python_heroku

2024/08/01 10:54

dameo様 コメントありがとうございます。 当方、普段からそこまでプログラミングやっている人間ではないもので、無作法失礼しました。 ただ、ご指摘頂き、いくつか気になりましたので、もしよろしければ教えて下さい。 前提として、元々の環境 python:ver3.8.0 pandas:1.1.3 SQLAlchemy:1.4.22 に関しては、DB接続、DB操作、トランザクション処理について出来ておりました。 そのため、論点の争点になるのが、今回のケースで言うとpandasやSQLAlchemyのversionパターンに伴うcreate_engineの作成方法ではないのか?と思ったのですが、違うのでしょうか? 特にpandas==2.1.4ではデータ操作まではできているので、つまりSQLAlchemyのコネクション関連の問題なのでは?と思っています。 環境構築用のScriptについては申し訳ございません。DockerFileなど用意できれば良いのですが、私の力量で作成できず。。 OSやDBについてのVersionは下記となります。 OS:Debian buster DB:v17.3
退会済みユーザー

退会済みユーザー

2024/08/01 11:05

> create_engineの作成方法ではないのか?と思ったのですが、違うのでしょうか? 違います > 環境構築用のScriptについては申し訳ございません。DockerFileなど用意できれば良いのですが、私の力量で作成できず。。 では質問もやめたほうがいいですね。
guest

回答3

0

回答ではありません

環境構築&調査用の中途半端なスクリプトです。
すでに一度解決済みになっているので、解説はしません。

bash

1mkdir data python_old python_new 2chmod a+w data 3cat >entry.sh <<EOF 4entrypoint=/sleep.sh 5kill_child() { 6 output=\$(ps -o pid,pgid,args) 7 pids=\$( 8 echo "\$output" | 9 sed '/ps -o pid,pgid,args *\$/d;/bash \\/entry.sh *\$/d' | 10 awk '\$2~/^'\$\$'\$/{print \$1;}' | 11 sed '/'\$\$'/d' 12 ) 13 kill \$pids 14} 15trap "echo trapped;kill_child;wait;exit 1" INT TERM 16bash -c "sleep infinity" & 17wait 18echo "entry finished" 19exit 0 20EOF 21cat >docker-compose.yml <<EOF 22services: 23 db: 24 image: mcr.microsoft.com/mssql/server:2019-latest 25 volumes: 26 - ./data:/var/opt/mssql 27 ports: 28 - 1433:1433 29 environment: 30 ACCEPT_EULA: Y 31 MSSQL_PID: Express 32 MSSQL_SA_PASSWORD: yourStrong(!)Password 33 python_old: 34 image: python:3.8 35 volumes: 36 - ./python_old:/home/python 37 - ./entry.sh:/entry.sh 38 user: "1000:1000" 39 working_dir: /home/python 40 environment: 41 HOME: /home/python 42 command: bash /entry.sh 43 python_new: 44 image: python:3.12 45 volumes: 46 - ./python_new:/home/python 47 - ./entry.sh:/entry.sh 48 user: "1000:1000" 49 working_dir: /home/python 50 environment: 51 HOME: /home/python 52 command: bash /entry.sh 53EOF 54docker compose up -d 55SA_PASS='yourStrong(!)Password' 56cat >wait_db_started.sh <<EOF 57while ! /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P '${SA_PASS}' </dev/null 2>/dev/null;do 58 sleep 1 59done 60EOF 61docker compose exec -T db bash -x <wait_db_started.sh 62cat >initialize_db.sql <<EOF 63CREATE DATABASE TestDB COLLATE Japanese_CI_AS; 64go 65SELECT Name from sys.databases; 66go 67CREATE LOGIN testuser WITH PASSWORD = '${SA_PASS}'; 68go 69USE TestDB; 70go 71CREATE USER testuser FROM LOGIN testuser; 72go 73ALTER ROLE db_ddladmin ADD MEMBER testuser; 74go 75ALTER ROLE db_datawriter ADD MEMBER testuser; 76go 77ALTER ROLE db_datareader ADD MEMBER testuser; 78go 79EOF 80docker compose exec -T db /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "${SA_PASS}" -e <initialize_db.sql 81cat >initialize_tables.sql <<EOF 82USE TestDB; 83go 84CREATE TABLE Inventory (id INT PRIMARY KEY, name NVARCHAR(50), quantity INT); 85go 86SET IMPLICIT_TRANSACTIONS ON; 87go 88INSERT INTO Inventory VALUES (1, 'banana', 150); 89go 90INSERT INTO Inventory VALUES (2, 'orange', 154); 91go 92INSERT INTO Inventory VALUES (3, 'バナナ', 180); 93go 94SELECT * FROM Inventory; 95go 96commit; 97go 98EOF 99docker compose exec -T db /opt/mssql-tools/bin/sqlcmd -S localhost -U testuser -P "${SA_PASS}" -e <initialize_tables.sql 100cat >setup_drivers.sh <<EOF 101curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg 102curl https://packages.microsoft.com/config/debian/12/prod.list | tee /etc/apt/sources.list.d/mssql-release.list 103apt-get update 104ACCEPT_EULA=Y apt-get install -y msodbcsql18 105ACCEPT_EULA=Y apt-get install -y mssql-tools18 106apt-get install -y unixodbc-dev 107apt-get install -y libgssapi-krb5-2 108EOF 109cat >setup_venv_1.sh <<EOF 110if [ ! -d env1 ]; then 111 python3 -m venv env1 112fi 113. env1/bin/activate 114pip install -U pip setuptools 115pip install sqlalchemy==1.4.22 pandas==1.1.3 pyodbc 116deactivate 117EOF 118cat >setup_venv_2.sh <<EOF 119if [ ! -d env2 ]; then 120 python3 -m venv env2 121fi 122. env2/bin/activate 123pip install -U pip setuptools 124pip install sqlalchemy==1.4.22 pandas==2.2.2 pyodbc 125deactivate 126EOF 127cat >setup_venv_3.sh <<EOF 128if [ ! -d env3 ]; then 129 python3 -m venv env3 130fi 131. env3/bin/activate 132pip install -U pip setuptools 133pip install sqlalchemy==1.4.36 pandas==2.1.4 pyodbc 134deactivate 135EOF 136cat >setup_venv_4.sh <<EOF 137if [ ! -d env4 ]; then 138 python3 -m venv env4 139fi 140. env4/bin/activate 141pip install -U pip setuptools 142pip install sqlalchemy pandas pyodbc 143deactivate 144EOF 145for service in python_old python_new; do 146 docker compose exec -u root:root -T ${service} bash -x <setup_drivers.sh 147 for venvsh in ./setup_venv_*.sh; do 148 docker compose exec -T ${service} bash <${venvsh} 149 done 150 cat >$service/sqlalchemy_test_1.py <<EOF 151import traceback 152import pandas as pd 153from sqlalchemy import create_engine 154engine = create_engine( 155 "mssql+pyodbc://{user_id}:{password}@{host}:{port}/{dbname}?driver={driver}".format( 156 host = "db", 157 port = "1433", 158 dbname = "TestDB", 159 user_id = "testuser", 160 password = "yourStrong(!)Password", 161 driver = "ODBC Driver 18 for SQL Server" 162 ), 163 connect_args={'TrustServerCertificate': 'yes'} 164) 165 166df1 = pd.DataFrame([[4,"みかん", 300],], columns=["id", "name", "quantity"]) 167df2 = pd.DataFrame([[5,"りんご", 200],], columns=["id", "name", "quantity"]) 168df3 = pd.DataFrame([[6,"もも", 250],], columns=["id", "name", "quantity"]) 169tablename= 'inventory' 170 171with engine.connect() as conn: 172 with conn.begin() as tran: 173 try: 174 df1.to_sql(tablename, conn, index=False, if_exists="append") 175 raise Exception("test") 176 df2.to_sql(tablename, conn, index=False, if_exists="append") 177 tran.commit() 178 except Exception: 179 tran.rollback() 180 print(traceback.format_exc()) 181 with conn.begin() as tran: 182 try: 183 df2.to_sql(tablename, conn, index=False, if_exists="append") 184 df3.to_sql(tablename, conn, index=False, if_exists="append") 185 tran.commit() 186 print("success") 187 except Exception: 188 tran.rollback() 189 print(traceback.format_exc()) 190EOF 191 cat >$service/sqlalchemy_test_2.py <<EOF 192import traceback 193import pandas as pd 194from sqlalchemy import create_engine 195engine = create_engine( 196 "mssql+pyodbc://{user_id}:{password}@{host}:{port}/{dbname}?driver={driver}".format( 197 host = "db", 198 port = "1433", 199 dbname = "TestDB", 200 user_id = "testuser", 201 password = "yourStrong(!)Password", 202 driver = "ODBC Driver 18 for SQL Server" 203 ), 204 connect_args={'TrustServerCertificate': 'yes'} 205 #, isolation_level="READ COMMITTED" 206) 207 208df1 = pd.DataFrame([[4,"みかん", 300],], columns=["id", "name", "quantity"]) 209df2 = pd.DataFrame([[5,"りんご", 200],], columns=["id", "name", "quantity"]) 210df3 = pd.DataFrame([[6,"もも", 250],], columns=["id", "name", "quantity"]) 211tablename= 'inventory' 212 213with engine.connect() as conn: 214 with conn.begin(): 215 try: 216 df1.to_sql(tablename, conn, index=False, if_exists="append") 217 raise Exception("test") 218 df2.to_sql(tablename, conn, index=False, if_exists="append") 219 conn.commit() 220 except Exception: 221 conn.rollback() 222 print(traceback.format_exc()) 223 with conn.begin(): 224 try: 225 df2.to_sql(tablename, conn, index=False, if_exists="append") 226 df3.to_sql(tablename, conn, index=False, if_exists="append") 227 conn.commit() 228 print("success") 229 except Exception: 230 conn.rollback() 231 print(traceback.format_exc()) 232EOF 233 cat >$service/assert_reset.sql <<EOF 234select * from inventory; 235go 236delete from inventory where id between 4 and 6; 237go 238EOF 239 for env in 1 2 3 4; do 240 docker compose exec -T ${service} bash <<EOF 241. env${env}/bin/activate 242pip list 243python sqlalchemy_test_1.py 244/opt/mssql-tools18/bin/sqlcmd -S db -d TestDB -U testuser -P "${SA_PASS}" -C -e <assert_reset.sql 245python sqlalchemy_test_2.py 246/opt/mssql-tools18/bin/sqlcmd -S db -d TestDB -U testuser -P "${SA_PASS}" -C -e <assert_reset.sql 247deactivate 248EOF 249 done 250done 2>&1 | tee setup.log

投稿2024/08/02 00:11

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自己解決

自己解決できました。
pandas==2.1.4においてcreate_engineは作成出来るが、トランザクション処理ができない、という件についてSQLでトランザクションを明示的に実行すればトランザクション処理できました。
要件としては満たせるので、これで対応したいと思います。

pandas=2.2.2の方でcreate_engineを作成する方法は相変わらず出来なかったので、こちらはもしよろしければ教えて頂けると助かります。

python

1with engine.connect() as conn: 2 try: 3 conn.execute('BEGIN TRANSACTION') 4 df.to_sql(tabel, conn, if_exists="append") 5 conn.execute('BEGIN COMMIT') 6 except Exception as ex: 7 conn.execute('ROLLBACK') 8

投稿2024/08/01 13:06

python_heroku

総合スコア23

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ごめんなさい。回答に失敗して2回目です・・

警告は実行時に表示されるものでしょうか?
次のようなコードで試したところ警告もエラーもないようでした。

py

1import pandas as pd 2from sqlalchemy import create_engine 3engine = create_engine("sqlite:////absolute/path/to/foo.db") 4df = pd.DataFrame([ 5 { 'title': 'title1', 'year': 2001, 'score': 11 }, 6 { 'title': 'title2', 'year': 2002, 'score': 12 }, 7 { 'title': 'title3', 'year': 2003, 'score': 13 }, 8 { 'title': 'title4', 'year': 2004, 'score': 14 }, 9]) 10tablename = 'movie' 11with engine.begin() as conn: 12 try: 13 df.to_sql(tablename, conn, if_exists='append') 14 raise Exception('test exception') 15 conn.commit() 16 print('commit') 17 except Exception as ex: 18 conn.rollback() 19 print(ex)

to_sqlはデフォルトではテーブルの作り直しみたいですので、drop tableはdml(データ操作)ではなく、ddl(データ定義)なので、完全にはロールバックはできないと思います。
(ロールバックによってdrop,createの結果からテーブルが空っぽの状態になるみたいです。)

接続文字列はデータベースによって異なると思いますので、下の「参考」のリンク先を参考にしてみてください。

警告は、Stack Overflowによると、接続文字列の記述の仕方によるもののように思いましたので、このあたりを見直してみると良いかもしれません。
(ダメそうでしたらデータベースの種類やバージョンなどの環境面の情報も質問欄に追記してみてください)
sql server - Getting a warning when using a pyodbc Connection object with pandas - Stack Overflow

環境

Python 3.12.4
pandas 2.2.2
SQLAlchemy 2.0.31

参考

Engine Configuration — SQLAlchemy 2.0 Documentation
pandas.DataFrame.to_sql — pandas 2.2.2 documentation

投稿2024/07/31 12:21

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

python_heroku

2024/08/01 06:28

回答ありがとうございます。 頂いた参考情報なども見て、create_engineの作り方を修正するなども試してもみたのですが、自己解決できずでした。 pandas==2.1.4ではto_sqlの処理までは完了できますが、やはりconn.commit()やconn.rollbackが同じようにwithwith句のインデント内に含まれる形に修正してもて引き続き、同エラーが発生していました。 環境情報についてですが、pyodbcを利用してMSのSQL Serverに対して接続しようとしている、かつDriverはODBC Driver 17 for SQL Serverを利用していますが、他に必要事項あればご指摘ください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問