【プログラミング】SQLite3:エスケープ処理(特にダブルクォーテーション、シングルクォーテーションに関して)

  • URLをコピーしました!
目次

SQLite3

前回、plotlyでrangeselectorでワンクリックで表示範囲を変更する方法を紹介しました。

今回はちょっと苦しめられたSQLite3でのエスケープ処理を解説していきます。

PythonでSQLite3を使うと文字列としてコマンドを入力するため、ダブルクォーテーションやシングルクォーテーションで囲みます。

そうするとPythonの文字列としてのダブルクォーテーションやシングルクォーテーションとSQLite3の文字列としてのダブルクォーテーションやシングルクォーテーションと干渉してしまい、エラーとなってしまうことが多々ありました。

ということでどういう場合に正常に処理でき、どういう場合にエラーとなるのか、またダブルクォーテーションやシングルクォーテーションをSQLite3の文字列として使いたい場合のエスケープ処理に関して色々と試してみたというのが今回のお話です。

それでは始めていきましょう。

準備と基本のプログラム

まずは準備と基本のプログラムからです。

準備としてデータベースとテーブルを作成し、文字列を1つ保存してみます。

テーブルの作成やデータの保存は何度もやるとエラーとなるので、別のセルで一度だけ実行するようにします。

import sqlite3

with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    cur.execute('CREATE TABLE test(id INTEGER PRIMARY KEY, text TEXT)')
    conn.commit()
with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    cur.execute('INSERT INTO test(id, text) values(0, "abcde")')
    conn.commit()
with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    data = cur.execute('SELECT * FROM test').fetchall()
    print(data)

実行結果
[(0, 'abcde')]

上記の例はPythonの文字列にはシングルクォーテーション、SQLite3の文字列にはダブルクォーテーションを使った場合で問題なく処理できています。

エラーとなる例とその対処

まずはSQLite3の文字列中に文字列としてダブルクォーテーションやシングルクォーテーションを入れようとしてエラーとなる例です。

with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    cur.execute('INSERT INTO test(id, text) values(1, "abc'de")')
    conn.commit()

実行結果
  Input In [8]
    cur.execute('INSERT INTO test(id, text) values(1, "abc'de")')
                                                             ^
SyntaxError: unterminated string literal (detected at line 3)
with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    cur.execute('INSERT INTO test(id, text) values(1, "abc"de")')
    conn.commit()

実行結果
---------------------------------------------------------------------------
OperationalError                          Traceback (most recent call last)
Input In [9], in <cell line: 1>()
      1 with sqlite3.connect('text1.db') as conn:
      2     cur = conn.cursor()
----> 3     cur.execute('INSERT INTO test(id, text) values(1, "abc"de")')
      4     conn.commit()

OperationalError: near "de": syntax error

どちらもSyntax errorが出ていますが、エラーの出どころが違うようです。

最初の例ではPythonの文字列として終端していない(閉じられていない)ため、実行すらされていません。

2番目の例では実行はされていますが、SQLite3として「”abc”de”」だと「”abc”」までが文字列として認識され、「de”」が何か分からない状態となってしまいエラーとなってしまったようです。

文字列中にダブルクォーテーションやシングルクォーテーションを入れたい場合、エスケープ処理が必要になります。

SQLite3のダブルクォーテーションやシングルクォーテーションのエスケープ処理は、ダブルクォーテーションやシングルクォーテーションを重ねることでエスケープ処理となります。

with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    cur.execute('INSERT INTO test(id, text) values(1, "abc""de")')
    conn.commit()
with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    cur.execute("INSERT INTO test(id, text) values(2, 'abc''de')")
    conn.commit()
with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    data = cur.execute('SELECT * FROM test').fetchall()
    print(data)

実行結果
[(0, 'abcde'), (1, 'abc"de'), (2, "abc'de")]

注意点1:Pythonとは違うものを使う

ただしここで注意です。

上記2例のようにPythonの文字列に使用したダブルクォーテーションやシングルクォーテーションとは違うものを用いてください。

つまりPythonの文字列でシングルクォーテーションを使った場合は、SQLite3の文字列ではダブルクォーテーションがエスケープでき、逆にPythonの文字列でダブルクォーテーションを使った場合は、SQLite3の文字列ではシングルクォーテーションがエスケープできます。

Pythonの文字列と同じものをエスケープしようとすると単純にPythonの文字列が二つ並んだだけとなり、SQLite3のエスケープ処理としては働きません。

with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    cur.execute('INSERT INTO test(id, text) values(3, "abc''de")')
    conn.commit()
with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    cur.execute("INSERT INTO test(id, text) values(4, 'abc""de')")
    conn.commit()
with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    data = cur.execute('SELECT * FROM test').fetchall()
    print(data)

実行結果
[(0, 'abcde'), (1, 'abc"de'), (2, "abc'de"), (3, 'abcde'), (4, 'abcde')]

注意点2:ダブルクォーテーション、シングルクォーテーション自体がエスケープ文字ではない

もう一つの注意点としてはダブルクォーテーション、シングルクォーテーション自体がエスケープ文字ではないということです。

あくまでもダブルクォーテーションやシングルクォーテーションを2つ並べることで一つがエスケープ文字として、もう一つが文字列として認識されるということです。

つまりダブルクォーテーション+シングルクォーテーションの並びではエスケープできませんし、その逆でもエスケープできません。

with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    cur.execute('INSERT INTO test(id, text) values(5, "abc'"de")')
    conn.commit()

実行結果
  Input In [22]
    cur.execute('INSERT INTO test(id, text) values(5, "abc'"de")')
                                                                ^
SyntaxError: unterminated string literal (detected at line 3)
with sqlite3.connect('text1.db') as conn:
    cur = conn.cursor()
    cur.execute('INSERT INTO test(id, text) values(5, "abc"'de")')
    conn.commit()

実行結果
  Input In [24]
    cur.execute('INSERT INTO test(id, text) values(5, "abc"'de")')
                                                              ^
SyntaxError: unterminated string literal (detected at line 3)

Python上でSQLite3を使うとダブルクォーテーションとシングルクォーテーションの使い分けが重要になってくるようです。

もしかしたらもっと良い処理方法があるかもしれないので、見つけたら記事を書きたいと思います。

次回はPandasのデータフレームをそのままHTMLに変換する方法を紹介します。

ではでは今回はこんな感じで。

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

目次