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

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

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

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

3292閲覧

unrecognized tokenの解決方法

shirachin1015

総合スコア6

SQLite

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2023/02/06 11:45

実現したいこと

MQLで出ているunrecognized tokenエラーを解決したい

前提

Pythonのsqlite3を利用してデータベース操作の関数を実装しています。
機能全体で実現したいことは、データベースのUPDATE関数を作成し、関数の入力から合致したIDのデータを書き換える関数を実装したいです。
INSERTやDERETE、簡易的なview関数(該当するIDのデータを表示する関数)は作成できたのですが、UPDATEを実装した関数のみエラーが出てしまいます。
SQLに関しては初めて触っていて、SQL側で起こっているエラーなのかが全く検討つかずエラーを解決できません。
どなたか手を貸していただけると幸いです。よろしくお願いします。

teratail自体も初めて使っているので、情報などに不備があるとは思いますがその時は質問にも答えさせていただきますのでよろしくお願いいたします。

データベースの作成にDjangoを用いており、Djangoの圏外から別の.pyを用いてアクセスしている状況です。

発生している問題・エラーメッセージ

File "/.../dev/AutoPost/AutoPost/../crawler/test.py", line 34, in <module> postdb.DB_update('001', data) File "/.../dev/AutoPost/crawler/postdb.py", line 24, in DB_update cursor.execute(sql) sqlite3.OperationalError: unrecognized token: "{"

該当のソースコード

Python3

1# postdb.py データベース操作関連 2import sqlite3 3import pandas as pd 4 5... 6 7# 動作成功しているデータベースにデータを登録する関数 8# id(str) : データベースでprimary_keyとして登録しているデータ 9# content(str) : json形式で書かれたstrデータ 10 11def DB_register(id, content): 12 ins = (id, content) 13 cursor.execute(f'''INSERT INTO {tablename} values(?,?)''', ins) 14 15 16# 現在エラーが出ているデータベースの情報を更新する関数 17# id(str) : データベースでprimary_keyとして登録しているデータ 18# content(str) : json形式で書かれたstrデータ 19 20def DB_update(id, content): 21 sql = f''' 22 UPDATE {tablename} 23 SET postContent = {content} 24 WHERE postID = {id} 25 ''' 26 cursor.execute(sql) 27 28... 29 30dbname = ('../AutoPost/dataList.sqlite3') 31tablename = 'APapp_PostData' 32conn = sqlite3.connect(dbname, isolation_level=None) 33cursor = conn.cursor()

Python3

1# models.py Django内のファイル django > app > models.py 2from django.db import models 3 4... 5 6class PostData(models.Model): 7 postID = models.IntegerField(primary_key=True) 8 postContent = models.TextField()

Python3

1# test.py 動作テストに使用しているPythonファイル 2import postdb 3import userdb 4 5data = '''{ 6 "sample1" : "test", 7 "sample2" : { 8 "sample3" : "test", 9 "sample4" : "test" 10 }, 11 "sample5" : "test", 12 ... 13}''' 14 15postdb.DB_update('001', data) 16postdb.DB_view()

試したこと

はじめに、変数dataの中身を変えてテストしながら開発していたのでjsonの文法を確認しましたが、正常でした。
次に、データベースを初期化し

Python3

1postdb.DB_register('001', data)

を実行したところ正常に動作しました。

環境

Macbook Pro 2019
macOS Ventura 13.0.1

Python 3.9.6
Django 4.1.5
django.db.backends.sqlite3

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

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

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

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

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

shirachin1015

2023/02/06 11:53

足りていなかったので追記します。 自分のわからないことは、「このエラーはどういう意味?」ではなくて、「どうしてINSERTが大丈夫でUPDATEでエラーが出るの?」です。 この疑問に対して検索はしたのですが、「python sqlite3」でのエラーの情報を得られませんでした。
melian

2023/02/06 12:14

INSERT では parameterized query が使われていますが、UPDATE は「直書き」だからです。
shirachin1015

2023/02/06 12:24

SQL文にはpythonのf文字列を使用して変数の使用を実装したつもりだったのですが、それもUPDATEだと使えないのですか?
melian

2023/02/06 12:32

f-string と parameterized query は全くの別物なのです。それに、parameterized query を利用することで SQL injection を防ぐこともできますので、UPDATE でも parameterized query の利用をお勧めします。
guest

回答2

0

自己解決

皆さんご回答ありがとうございました。
質問側コメント欄でいただいた melian 様 のアドバイスにより、問題を解決することができました。
自己解決ではありませんが、解決済みにするため自己解決とさせていただきます。

melian 様のコメント

INSERT では parameterized query が使われていますが、UPDATE は「直書き」だからです。

このコメントをいただいた後、自分でいろいろ調べた結果このコメント通りUPDATEのSQLクエリ分にf文字列が適用できないことに気づき、実際に.format()などを試した結果、確かにpythonの文字列フォーマットが適用できていませんでした。
内部的な原因までは辿り着いていませんが、解決策を見つけることができたので回答募集を終了させていただきました。
具体的な解決策は、parameterized query などのワードを調べて辿り着いたこちらのサイトを参考にさせていただきました。

https://qiita.com/tep731/items/b8a4b40c3765f250fdd9

上記サイトを参考に、プログラムを次のように変更しました。

Python3

1# 変更前 2def DB_update(id, content): 3 sql = f''' 4 UPDATE {tablename} 5 SET postContent = {content} 6 WHERE postID = {id} 7 ''' 8 cursor.execute(sql) 9 10# 変更後 11def DB_update(id, content): 12 ins = { 13 "id" : id, 14 "content" : content 15 } 16 sql = ''' 17 UPDATE APapp_PostData 18 SET postContent = :content 19 WHERE postID = :id 20 ''' 21 cursor.execute(sql, ins)

parameterized query を利用することで SQL injection を防ぐこともできますので、UPDATE でも parameterized query の利用をお勧めします。 (melian 様コメントより)

いただいたこちらのコメントにもあるようにセキュリティー面も考慮した結果、この方法をとった方が安全という事なので全ての関数にこのパラメータクエリを実装しました。

ご回答有難うございました。

投稿2023/02/06 13:08

shirachin1015

総合スコア6

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

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

0

詳しくはありませんが、エラーは変なところに「{」が入っていると言っていますので、

python

1 sql = f''' 2 UPDATE {tablename} 3 SET postContent = {content} 4 WHERE postID = {id} 5 '''

ここで、入れている content、元は data のところがおかしいのでしょう。
data変数に入っているのはjson文字列のようですが、表示してみれば、このやりかたでは、そのまま{content}の部分に入ってしまいます。 「""」などで囲む必要があるのではないかと思います。


追記
tablenameが「APapp_PostData」で、idが「001」contentが「{ "sample1" : "test" }」だとすると、sqlはこうなります。

text

1 UPDATE APapp_PostData 2 SET postContent = { "sample1" : "test" } 3WHERE postID = 001

これは想定どおりでしょうか? とうことです。

投稿2023/02/06 11:57

編集2023/02/06 13:12
TakaiY

総合スコア12765

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

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

shirachin

2023/02/06 11:59

このデータをそのままDB_registerに入れると正常に動作するのはなぜなのでしょう?
TakaiY

2023/02/06 13:05 編集

それは、その文字列がコマンドの一部ではなく、文字列として取り込まれているからです。 それを入れるとき、「''」で囲ったりしませんか? ちょっと追記します。
shirachin1015

2023/02/06 13:24

例えば、"{content}"としたら、contentの中身はデータベースに格納出来ないなとなってしまって詰んでしまった契機がありました。現時点では解決済みですが、その時は少しpython sqlite3 について勉強不足だったなと自覚しております。 遅くなりましたが、追記有難うございました。今回はmelian様の回答から解決する方が少し早くなってしまいベストアンサーに選ぶ事が出来ませんでしたが、また機会があればご回答いただけると嬉しいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問