質問ポイント
pandas DataFrameからSqlite3のIndexありテーブル(自動付与インクリメント)にデータ追加できない。
Index(自動付与)しなければIndex項目が自動的に発生するが追加データ内部連番が追加されてる。
当方のパソコン環境
Win10 python 3.10 64bit pandas 1.4.2 Sqlite 3.39.4
pythonでpandasとsqlite3勉強中。
ファイルをpandasで読み込んで、
DBにテーブル作成が簡単にできました。
項目名対応も自動的にしてくれるすぐれもの。
ところが、データ追加するとindexが期待したようになりません。
テーブルにindexをユニーク・インクリメント自動に設定したところ
なってほしいのは、indexに連番でデータを自動追加してくれることなのに、
全データ削除後に1回だけできましたが、続けてのappendできません。
左側に管理番号らしき項目名のない連番が発生。
DB Browser for SQlite3のテーブル情報 indexは PRIMARY KEY("index" AUTOINCREMENT)
CREATE TABLE "df_sqlite_model" (
"index" INTEGER NOT NULL,
"id" TEXT,
"A" TEXT,
"B" INTEGER,
"C" TEXT,
PRIMARY KEY("index" AUTOINCREMENT)
);
このindexつけると、データ全削除後に、1回だけappendできるけど、次にappendはエラーに。
1回だけ成功したTable(データは3件)がこれです。
index id A B C
0 0 100' ab 10 black
1 1 200' cd 20 red
2 2 300' ef 30 yellow
pandas DataFrameを、既存テーブルある時はtableをreplaceにすると
indexの自動付与インクリメントがなくなり、そうなると
正常動作して、appendもできデータ数は全部で6件になりましたがindexは追加データ内部連番で、
追加するごとに 0 1 2 0 1 2 のようになって重複しまくり。
pythonプログラムは下記になります
--------------------------------------
import sqlite3
import pandas as pd
file_1="sample_df_001.csv"
file_2="sample_df_002.csv"
df_1= pd.read_csv(file_1)
print("df_1= \n", df_1) #入れたいsampleデータ1 表示
## df_1=
## id A B C
## 0 100' ab 10 black
## 1 200' cd 20 red
## 2 300' ef 30 yellow
df_2= pd.read_csv(file_2)
print("df_2= \n", df_2) #入れたいsampleデータ2 表示(項目順変更)
## df_2=
## id B C A
## 0 100' 10 black ab
## 1 200' 20 red cd
## 2 300' 30 yellow ef
dbfile = "test.db"
tbl_name = "df_sqlite_model"
query = "select * from " + tbl_name #query作成
with sqlite3.connect(dbfile) as con: #データベースに接続 con
#テーブル名が存在している場合:‘fail’, ‘replace’, ‘append’
df_1.to_sql(tbl_name,con,if_exists='replace')
df_2.to_sql(tbl_name,con,if_exists='append')
q_to_df = pd.read_sql_query(query,con)
print(q_to_df)
DBのテーブルをpandas DataFrameで読みだしたものがこれ
自動でついたIndexは重複していて元データのものがそのまま、さらに左側に連番項目あり
## index id A B C
## 0 0 100' ab 10 black
## 1 1 200' cd 20 red
## 2 2 300' ef 30 yellow
## 3 0 100' ab 10 black
## 4 1 200' cd 20 red
## 5 2 300' ef 30 yellow
No.3ベストアンサー
- 回答日時:
>自動インクリメント型のプライマリーキーが期待された動作をしないということのようです。
>https://ytyaru.hatenablog.com/entry/2021/06/17/0 …
上記拝見しました。
pandas使用時、indexを未使用にして、indexの代わりにseqを項目名にします。そして、これを自動インクリメント型のプライマリーキーにします。
以下のような定義になります。
CREATE TABLE "df_sqlite_model" (
"seq" INTEGER NOT NULL,
"id" TEXT,
"A" TEXT,
"B" INTEGER,
"C" TEXT,
"D" TEXT,
"E" TEXT,
PRIMARY KEY("seq" AUTOINCREMENT)
);
上記の定義で、if_exists='append'のみを使えば、seqは期待した結果になります。(if_exists='replace'は使用しない)
スクリプトは、以下になります。
with sqlite3・・・より後の行はインデントがあります。
(このサイトに投稿するとインデントがなくなります。)
-----------------------------------
import sys
import sqlite3
import pandas as pd
file_1="sample_df_001.csv"
file_2="sample_df_002.csv"
df_1= pd.read_csv(file_1)
print("df_1= \n", df_1) #入れたいsampleデータ1 表示
df_2= pd.read_csv(file_2)
print("df_2= \n", df_2) #入れたいsampleデータ2 表示(項目順変更)
dbfile = "test.db"
tbl_name = "df_sqlite_model"
query = "select * from " + tbl_name #query作成
with sqlite3.connect(dbfile) as con: #データベースに接続 con
df_1.to_sql(tbl_name,con,if_exists='append',index=False)
df_2.to_sql(tbl_name,con,if_exists='append',index=False)
q_to_df = pd.read_sql_query(query,con)
print(q_to_df)
以下実行結果
df_1=
id A B C
0 100 ab 10 black
1 200 cd 20 red
2 300 ef 30 yellow
df_2=
id B C A
0 100 10 black ab
1 200 20 red cd
2 300 30 yellow ab
seq id A B C D E
0 1 100 ab 10 black None None
1 2 200 cd 20 red None None
2 3 300 ef 30 yellow None None
3 4 100 ab 10 black None None
4 5 200 cd 20 red None None
5 6 300 ab 30 yellow None None
https://ytyaru.hatenablog.com/entry/2021/06/17/0 …
でいろいろ問題がかかれていますが、
実行結果をみると、seqはきちんと採番されています。
通常の操作をする分には、特に問題なく使えるのではないかと思います。
(pandasと自動採番項目は相性が悪いですが、それは他のDBでも同じことかと思います)
なるほど、いろいろあるのですね。
pandas使うと便利が多いので、使える方法提示はありがたいです。
私も、一件ずつSQLでInsert登録試したら、正常に機能を確認できました。
内容は以下です。
import sqlite3
import pandas as pd
dbname = 'test.db'
table = "user" #今回の対象テーブル名
con = sqlite3.connect(dbname)
cur = con.cursor()
query1 = "CREATE TABLE IF NOT EXISTS user(id integer primary key, name text);"
cur.execute(query1)
#1件ずつ挿入
query2 = "insert into user(name) values('Harada')"
cur.execute(query2)
query2 = "insert into user(name) values('Yamada')"
cur.execute(query2)
query2 = "insert into user(name) values('Tani')"
cur.execute(query2)
#登録データリストにし
##r = [('Harada2'), ('Yamada2'), ('Tani2')]
#一括登録はエラーに
##query3 = "INSERT INTO user(name,) VALUES (?,)"
##cur.executemany(query3, r) #エラーになりました。
query3 = "select * from user "
q_df = pd.read_sql_query(query3, con)
print(q_df)
#2回実施したらIDが順に増えていました。
## id name
## 0 1 Harada
## 1 2 Yamada
## 2 3 Tani
## 3 4 Harada
## 4 5 Yamada
## 5 6 Tani
con.commit()
con.close()
No.5
- 回答日時:
>この経験から、使いやすいアプリからデータを扱うのが生産性高く効率的だと実感しています。
おっしゃる通りです。まずは、使いやすい、慣れたものを使うのが一番かと思います。
>pythonからだと、いろいろ扱えるということで、勉強中ですが、思いがけないことも多く、出来上がったら便利だけど、使えるようになるまでは面倒多いとも感じています。
同感です。
私は、年金暮らしのジジイですが、知識を吸収する余力がなくて困ってます。新しいことを覚えてもすぐに忘れるので、なかなか覚えられません。
pythonを書くときは、マニュアルをみながらでないと正しい構文が書けません。やはり、使えるようになるまでは面倒も多いですね。
といっても、まあ、暇つぶしにやっているところもあるので、特に切羽詰まっているわけではないのですが。
私ももうすぐ後期高齢者入り、同じ画面にないと(見てでないと)プログラム入力のキーボードをたたけません(記憶力が超減衰)。
プログラム学習はボケ防止と、暇つぶしに最適でもあり、若い人の話についていくためにやってます。
pythonで、簡単にできたのは新聞記事のスクレイピング。これは、少ない行数でできた。モジュール活用がポイントでした。
エクセルをDBソフトからGUIで扱えるAccessは、30年以上前から常用していますが、同じことをPythonなどからやろうとすると、とてつもなくハードルが高いので、資料調査の生産性という面では、前者が圧倒的に高いです。
Accessをエクセル見るための便利モジュールとして使うと割り切ればよいと。
ただ、AccessでDB構築はすさまじくハードル高いのであきらめてます。
No.4
- 回答日時:
>プロの皆様はどうしているのでしょう?
私は、プロではありませんが、下記のサイトをみると、Primary Keyの問題はプロの方もいろいろと手をやいているみたいですね。
https://qiita.com/mynkit/items/b329ce4f9d6c22938 …
まだ、pandasには実装されていませんが、upsertの機能を追加する予定だそうです。
if_exists='upsert_keep'
if_exists='upsert_overwrite'
のどちらかを指定して、行う方法です。
この機能が実装されれば、あなたが望んでいたことがすんなりとできるようになるかと思います。
紹介いただいたサイトは、判りやすく誰にでも参考になるように
短く簡単なモデルでプログラムを書かれていて、勉強になりました。
Pandas DataFrame使うと、簡単に表現したい内容に作ってくれて大変便利。
1行で済んでしまう。これが使えるようにしてくれそうです。
この世界、いろいろな人が寄り集まって改善していってるのが実感。
ありがとうございます。
No.2
- 回答日時:
>通常のDBと同じように使えるかどうか、試してみているのですが、どうも期待通りというわけにはいかないようです。
これはpandas側の問題で、sqlite3は正常に動作していると考えられます。
CREATE TABLEで、index,id,A,B,Cの項目を作成していますが、これを
index,id,A,B,C,E,F,Gのように作成して、to_sql(if_exists='replace')
をおこなうと、項目E,F,Gは生成されません。
pandas側にしてみれば、テーブルを削除後、再作成するとき、以前のテーブルと全く同じものを作る意図は全くないように見えます。
pandasにとって,DBはCSVファイルとかexcelファイルとかのように、今pandasが格納しているデータを保存するための器であれば、それで良いと考えているように見えます。
関心を持っていただき、感謝します。
小生は、頭の体操的に勉強しているので切羽詰まってるわけではありません。
ここ数日、この問題と格闘しましたが、やるたびに迷路に。
だんだんと分かってきたこと
先にテーブルをindex integer入れて定義し作成したものにpandas DataFrameを追加しようとするとエラーになる。
df.to_sql()で作成したテーブルには、dfにないindex integer項目が自動で付加され、データ追加するデータ群の内部連番が都度自動的に付加される。
その後のappendは、同様にできている。
ただ、これだと、プログラム作成するときに、データベース的な動作としては問題があるようにも思えます。
ただ、内部管理用か行番号が自動付与されてるが、これが行に固有についているものか、単に表示のためだけの連番か?
プロの皆様はどうしているのでしょう?
で、先ほどsqlite3のprimary keyで調べていたらこんなのがありました。
全部はよくわからないけど、どうもバグ的な問題があって、自動インクリメント型のプライマリーキーが期待された動作をしないということのようです。
https://ytyaru.hatenablog.com/entry/2021/06/17/0 …
膨大な内容があるので、引用紹介は差し控えますが、どうも「動作しない」と言ってるように思えます。
No.1
- 回答日時:
提示されたスクリプトの実行前と実行後のdf_sqlite_modelの構造を確認してみました。
実行前
sqlite> .schema
CREATE TABLE sqlite_sequence(name,seq);
CREATE TABLE IF NOT EXISTS "df_sqlite_model" (
"index" INTEGER NOT NULL,
"id" TEXT,
"A" TEXT,
"B" INTEGER,
"C" TEXT,
PRIMARY KEY("index" AUTOINCREMENT)
);
実行後
sqlite> .schema
CREATE TABLE sqlite_sequence(name,seq);
CREATE TABLE IF NOT EXISTS "df_sqlite_model" (
"index" INTEGER,
"id" INTEGER,
"A" TEXT,
"B" INTEGER,
"C" TEXT
);
CREATE INDEX "ix_df_sqlite_model_index"ON "df_sqlite_model" ("index");
indexのAUTOINCREMENT属性が失われています。
これが仕様なのかバグなのかわかりませんが、
if_exists='replace'を指定すると、テーブルを削除後、再作成したときに、
最初に作ったものと構造が変わることになります。
よって、AUTOINCREMENT属性を失いたくないなら、
「if_exists='replace'を使用しない」という選択肢しか残されていないかと思います。
どうしても、あなたがreplaceに期待する結果と同じことをやりたいなら、
その条件が発生したとき、SQLコマンドで
①当該テーブルの削除
②当該テーブルの生成
③to_sql(if_exists='append')での呼び出し
を行うしかないかと思います。
早速の回答、ありがとうございます。
そうなんですね。
通常のDBと同じように使えるかどうか、試してみているのですが、どうも期待通りというわけにはいかないようです。
これが、バグなのかどうかよくわかりませんが、
DB Browser(SQlite)の動作も何度か削除や設定してると、ロックしてしまいます。PCの再起動で直りますが、まだ未完成なシステムに思えてきました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・集中するためにやっていること
- ・テレビやラジオに出たことがある人、いますか?
- ・【お題】斜め上を行くスキー場にありがちなこと
- ・人生でいちばんスベッた瞬間
- ・コーピングについて教えてください
- ・あなたの「プチ贅沢」はなんですか?
- ・コンビニでおにぎりを買うときのスタメンはどの具?
- ・おすすめの美術館・博物館、教えてください!
- ・ことしの初夢、何だった?
- ・【お題】大変な警告
- ・【大喜利】【投稿~1/20】 追い込まれた犯人が咄嗟に言った一言とは?
- ・洋服何着持ってますか?
- ・みんなの【マイ・ベスト積読2024】を教えてください。
- ・「これいらなくない?」という慣習、教えてください
- ・今から楽しみな予定はありますか?
- ・AIツールの活用方法を教えて
- ・【お題】逆襲の桃太郎
- ・自分独自の健康法はある?
- ・最強の防寒、あったか術を教えてください!
- ・【大喜利】【投稿~1/9】 忍者がやってるYouTubeが炎上してしまった理由
- ・歳とったな〜〜と思ったことは?
- ・モテ期を経験した方いらっしゃいますか?
- ・好きな人を振り向かせるためにしたこと
- ・スマホに会話を聞かれているな!?と思ったことありますか?
- ・それもChatGPT!?と驚いた使用方法を教えてください
- ・見学に行くとしたら【天国】と【地獄】どっち?
- ・これまでで一番「情けなかったとき」はいつですか?
- ・この人頭いいなと思ったエピソード
- ・あなたの「必」の書き順を教えてください
- ・14歳の自分に衝撃の事実を告げてください
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
csvデータ不要列の削除をbatフ...
-
ACCESS VBAでSeekメソッドの処...
-
Accessでパラメーター以外の削...
-
追加クエリで重複データなしで...
-
ListBoxにAddItemする際、重複...
-
Excel VBAのユーザーフォームで...
-
自作アプリからAPIで他のアプリ...
-
EXCELで外部データの取り込みが...
-
【SQL】他テーブルに含まれる値...
-
フラグをたてるってどういうこ...
-
SELECT INTOで一度に複数の変数...
-
sqlに記述できない文字
-
UPDATEで既存のレコードに文字...
-
既存データをINSERT文にして出...
-
エラーを起こす方法
-
データ削除とSQL*Loaderでのイ...
-
同一テーブル内での比較(最新...
-
SQLで、Join句で結合したテ...
-
PostgreSQLのtimestamp型で時間...
-
T-SQLで任意の箇所で強制終了す...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
追加クエリで重複データなしで...
-
Excel VBAのユーザーフォームで...
-
pandasでsqlite3にテーブル作成...
-
JDBCを使ってdate型へのINSERT...
-
【VB】セルが空になるまで処理...
-
csvデータ不要列の削除をbatフ...
-
VBAでの行数を揃える方法
-
エクセル 2つの列にある値の完...
-
EXCELで外部データの取り込みが...
-
自作アプリからAPIで他のアプリ...
-
ACCESS VBAでSeekメソッドの処...
-
Accessでパラメーター以外の削...
-
マクロでファイルを読み込み、...
-
ListBoxにAddItemする際、重複...
-
一週間前から,今までVBAで行っ...
-
EXCEL2000からACCESS2000のテー...
-
Excel VBA でイベント"Workshee...
-
MySQLでauto_incrementをつかわ...
-
エクセルで去年のデータを今年...
-
コンボボックスを選択したい
おすすめ情報
普段は、WIN10パソコンで、エクセルデータをアクセスにリンクし、アクセスのデータベース操作機能(SQLのGUIあり)利用して、月次の実績などを見える化しています。
特定データの選択・グループ化・合計作成・作ったクエリーを元データにさらにクエリー作ることで、簡単にマスターを作ってリンクして複数データをリンクでき、実に便利です。
この経験から、使いやすいアプリからデータを扱うのが生産性高く効率的だと実感しています。
pythonからだと、いろいろ扱えるということで、勉強中ですが、思いがけないことも多く、出来上がったら便利だけど、使えるようになるまでは面倒多いとも感じています。