ちゃぱブログ / エンジニアリング / マネジメント

とあるプロダクトの運用組織のマネジメントしてる人の雑記。主にエンジニアリングやマネジメントのことを書きます。ときおりプチ情報も

(Python)SQLite3のSelect結果の取得

SQLite3を使ってSELECT文を実行したあとのデータの取得方法にはいくつか種類があります。それらの取得結果の違いや、用途のイメージについて記載します。

 

取得方法

取得方法は4つあります。

  • fetcthone()
  • fetchall()
  • fetchmany()
  • イテレータとして利用(こちらの説明は割愛)

 

それぞれについて、取得結果等の説明を記載する。

 

fetchone()

Pythonのオフィシャルには以下の記載があります。

クエリ結果から次の row をフェッチして、1つのシーケンスを返します。これ以上データがない場合は None を返します。

どういう結果になるか実装を見てみます。

import sqlite3
 
import sqlite3
conn = sqlite3.connect('sample.db')
 
c = conn.cursor()
 
SQL = '''
SELECT *
  FROM TBL_PRODUCT
'''
c.execute(SQL)
print(c.fetchone())
print(c.fetchone())

複数商品がデータ登録されている前提です。結果は次のようになります。

(1, 'サンプル商品', 'サンプル用の商品です')

(2, 'グッド商品', '良い商品です')

取得できた全量から1件ずつ取り出します。

主キーで取ってくる場合などは、これで取ると楽ですね。

fetchall()

Pythonのオフィシャルには以下の記載があります。

全ての(残りの)クエリ結果の row をフェッチして、リストを返します。cursor の arraysize 属性がこの操作のパフォーマンスに影響することに気をつけてください。これ以上の row がない場合は、空のリストが返されます。

「残りの」というところがミソですね。どういう結果になるか実装を見てみます。

import sqlite3
conn = sqlite3.connect('sample.db')
 
c = conn.cursor()
 
SQL = '''
SELECT *
  FROM TBL_PRODUCT
'''
c.execute(SQL)
print(c.fetchall())

結果は次のようになります。

[(1, 'サンプル商品', 'サンプル用の商品です'),(2, 'グッド商品', '良い商品です')]

リストで全データが取られます。

では続いて「残りの」というところを確認してみます。最初にfetchone()でひとつ取り出しておいてからfetchall()します。

import sqlite3
conn = sqlite3.connect('sample.db')
 
c = conn.cursor()
 
SQL = '''
SELECT *
  FROM TBL_PRODUCT
'''
c.execute(SQL)
print(c.fetchone())
print(c.fetchall())

結果は次のようになります。確かに「残り」がリストで返ってきました。

(1, 'サンプル商品', 'サンプル用の商品です')
[(2, 'グッド商品', '良い商品です')]

fetchmany()

Pythonのオフィシャルには以下の記載があります。

クエリ結果から次の幾つかの row をフェッチして、リストを返します。これ以上データがない場合は空のリストを返します。

一回の呼び出しで返される row の数は、size 引数で指定できます。この引数が与えられない場合、cursor の arraysize 属性が利用されます。このメソッドは可能な限り指定された size の数の row を fetch しようとするべきです。もし、指定された数の row が利用可能でない場合、それより少ない数の row が返されます。

size 引数とパフォーマンスの関係についての注意です。パフォーマンスを最適化するためには、大抵、 arraysize 属性を利用するのがベストです。 size 引数を利用したのであれば、次の fetchmany() の呼び出しでも同じ数を利用するのがベストです。

取得するデータ量を決めて取得することができます。どういう結果になるか実装を見てみます。

import sqlite3
conn = sqlite3.connect('sample.db')
 
c = conn.cursor()
 
SQL = '''
SELECT *
  FROM TBL_PRODUCT
'''
c.execute(SQL)
print(c.fetchmany())
c.execute(SQL)
print(c.fetchmany(2))

意外だったのが「fetchmany()」と引数を指定しないときでした。最初の予想では「fetchall()」と同じ結果になると想像していたのですが異なりました。

(1, 'サンプル商品', 'サンプル用の商品です')
[(1, 'サンプル商品', 'サンプル用の商品です'),(2, 'グッド商品', '良い商品です')]

公式の説明を見ると「この引数が与えられない場合、cursor の arraysize 属性が利用されます」とあります。なるほど。見てみましょう。

c.execute(SQL)
print(c.arraysize)
c.arraysize = 99
print(c.arraysize)

こうすると、

1
99

となりました。

初期値は「1」なんですね。そして、上のように書き換えられるんですね。初めて知りました。

さいごに

あまり普段はSQLite3を使ってデータ加工しないので意識してませんでしたが、調べ始めると色々と知らないことが出てきました。

オフィシャルだけではどういった結果になるのかのイメージがわかなかったので、これがどなたかの参考になればと思います。