sqliteクエリからdictを取得するにはどうすればよいですか?


118
db = sqlite.connect("test.sqlite")
res = db.execute("select * from table")

反復により、行に対応するリストを取得します。

for row in res:
    print row

列の名前を取得できます

col_name_list = [tuple[0] for tuple in res.description]

しかし、リストの代わりに辞書を取得するためのいくつかの機能または設定はありますか?

{'col1': 'value', 'col2': 'value'}

または私は自分でやらなければなりませんか?



3
@ vy32:この質問は2010年7月のもので、あなたがリンクしたのは2010年11月です。そして、予想通り、その逆のコメントが付けられました:-)
aneroid

回答:


158

ドキュメントの例のように、row_factoryを使用できます。

import sqlite3

def dict_factory(cursor, row):
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

con = sqlite3.connect(":memory:")
con.row_factory = dict_factory
cur = con.cursor()
cur.execute("select 1 as a")
print cur.fetchone()["a"]

または、ドキュメントのこの例の直後に示されているアドバイスに従ってください:

タプルを返すだけでは不十分で、列への名前ベースのアクセスが必要な場合は、row_factoryを高度に最適化されたsqlite3.Rowタイプに設定することを検討する必要があります。行は、メモリオーバーヘッドをほとんど発生させることなく、インデックスベースと大文字と小文字を区別しない名前ベースの両方で列にアクセスできます。おそらく、独自のカスタム辞書ベースのアプローチや、db_rowベースのソリューションよりも優れています。


お使いのカラム名は、それらの特殊文字を使用している場合などSELECT 1 AS "dog[cat]"、その後cursor辞書を作成するための正しい説明がありません。
クレイゾメーター

私は設定しconnection.row_factory = sqlite3.Rowconnection.row_factory = dict_factory示されているように試しましたcur.fetchall()が、それでもタプルのリストが表示されます-これが機能しない理由は何ですか?
displayname

@displaynameは、「ほとんどの機能でタプルを模倣しようとする」というドキュメントではありません。私はそれがあなたが得ることができるものにどういうわけか似ていると確信していますcollections.namedtuple。使用するcur.fetchmany()と、のようなエントリが表示されます<sqlite3.Row object at 0x...>
1

7年後でも、この回答は、私がSOで見つけたドキュメントから最も役立つコピーと貼り付けです。ありがとう!
WillardSolutions 2017

40

アダムシュミデグとアレックスマルテリの両方の回答で部分的に言及されているにもかかわらず、私はこの質問に答えると思いました。同じ質問を持つ私のような他の人のために、答えを簡単に見つけることができます。

conn = sqlite3.connect(":memory:")

#This is the important part, here we are setting row_factory property of
#connection object to sqlite3.Row(sqlite3.Row is an implementation of
#row_factory)
conn.row_factory = sqlite3.Row
c = conn.cursor()
c.execute('select * from stocks')

result = c.fetchall()
#returns a list of dictionaries, each item in list(each dictionary)
#represents a row of the table

21
現在、オブジェクトfetchall()を返すようsqlite3.Rowです。しかし、これらは単に使用して辞書に変換することができますdict()result = [dict(row) for row in c.fetchall()]
ゴンサロリベイロ2018

21

sqlite3.Rowクラスを使用する場合でも、次の形式で文字列フォーマットを使用することはできません。

print "%(id)i - %(name)s: %(value)s" % row

これを回避するために、行を取得して辞書に変換するヘルパー関数を使用します。これは、ディクショナリオブジェクトがロウオブジェクトよりも望ましい場合にのみ使用します(たとえば、ローオブジェクトがディクショナリAPIをネイティブでサポートしていない文字列フォーマットなど)。ただし、それ以外の場合は常にRowオブジェクトを使用してください。

def dict_from_row(row):
    return dict(zip(row.keys(), row))       

9
sqlite3.Rowはマッピングプロトコルを実装します。あなたはただすることができますprint "%(id)i - %(name)s: %(value)s" % dict(row)
Mzzzzzz 2015年


8

PEP 249から:

Question: 

   How can I construct a dictionary out of the tuples returned by
   .fetch*():

Answer:

   There are several existing tools available which provide
   helpers for this task. Most of them use the approach of using
   the column names defined in the cursor attribute .description
   as basis for the keys in the row dictionary.

   Note that the reason for not extending the DB API specification
   to also support dictionary return values for the .fetch*()
   methods is that this approach has several drawbacks:

   * Some databases don't support case-sensitive column names or
     auto-convert them to all lowercase or all uppercase
     characters.

   * Columns in the result set which are generated by the query
     (e.g.  using SQL functions) don't map to table column names
     and databases usually generate names for these columns in a
     very database specific way.

   As a result, accessing the columns through dictionary keys
   varies between databases and makes writing portable code
   impossible.

だから、はい、それを自分で行います。


>データベースによって異なります-sqlite 3.7と3.8のように?
Nucular

@ user1123466:... SQLite、MySQL、Postgres、Oracle、MS SQL Server、Firebird間など
Ignacio Vazquez-Abrams 14年


3

私のテストで最速:

conn.row_factory = lambda c, r: dict(zip([col[0] for col in c.description], r))
c = conn.cursor()

%timeit c.execute('SELECT * FROM table').fetchall()
19.8 µs ± 1.05 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)

対:

conn.row_factory = lambda c, r: dict([(col[0], r[idx]) for idx, col in enumerate(c.description)])
c = conn.cursor()

%timeit c.execute('SELECT * FROM table').fetchall()
19.4 µs ± 75.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

あなたが決める :)


1

前述のソリューションと同様ですが、最もコンパクトです。

db.row_factory = lambda C, R: { c[0]: R[i] for i, c in enumerate(C.description) }

これは私にとってはうまくいきましたが、上記の答えdb.row_factory = sqlite3.Rowは私にとってはうまくいきませんでした(JSON TypeErrorが発生したため)
Phillip

1

@gandalfの回答で述べたように、を使用する必要conn.row_factory = sqlite3.Rowがありますが、結果は直接辞書ではありませんdict最後のループで追加の「キャスト」を追加する必要があります。

import sqlite3
conn = sqlite3.connect(":memory:")
conn.execute('create table t (a text, b text, c text)')
conn.execute('insert into t values ("aaa", "bbb", "ccc")')
conn.execute('insert into t values ("AAA", "BBB", "CCC")')
conn.row_factory = sqlite3.Row
c = conn.cursor()
c.execute('select * from t')
for r in c.fetchall():
    print(dict(r))

# {'a': 'aaa', 'b': 'bbb', 'c': 'ccc'}
# {'a': 'AAA', 'b': 'BBB', 'c': 'CCC'}

1

私はあなたが正しい軌道に乗っていたと思います。これを非常にシンプルにして、あなたがやろうとしていたことを完了しましょう:

import sqlite3
db = sqlite3.connect("test.sqlite3")
cur = db.cursor()
res = cur.execute("select * from table").fetchall()
data = dict(zip([c[0] for c in cur.description], res[0]))

print(data)

欠点は.fetchall()、テーブルが非常に大きい場合、メモリ消費が殺されることです。しかし、ほんの数千行のテキストと数値列を扱う簡単なアプリケーションでは、この単純なアプローチで十分です。

深刻な問題については、他の多くの回答で提案されているように、行ファクトリを調べる必要があります。


0

または、次のようにsqlite3.Rowsを辞書に変換できます。これにより、各行のリストを含む辞書が作成されます。

    def from_sqlite_Row_to_dict(list_with_rows):
    ''' Turn a list with sqlite3.Row objects into a dictionary'''
    d ={} # the dictionary to be filled with the row data and to be returned

    for i, row in enumerate(list_with_rows): # iterate throw the sqlite3.Row objects            
        l = [] # for each Row use a separate list
        for col in range(0, len(row)): # copy over the row date (ie. column data) to a list
            l.append(row[col])
        d[i] = l # add the list to the dictionary   
    return d

0

3行だけを使用した一般的な代替

def select_column_and_value(db, sql, parameters=()):
    execute = db.execute(sql, parameters)
    fetch = execute.fetchone()
    return {k[0]: v for k, v in list(zip(execute.description, fetch))}

con = sqlite3.connect('/mydatabase.db')
c = con.cursor()
print(select_column_and_value(c, 'SELECT * FROM things WHERE id=?', (id,)))

ただし、クエリが何も返さない場合は、エラーになります。この場合...

def select_column_and_value(self, sql, parameters=()):
    execute = self.execute(sql, parameters)
    fetch = execute.fetchone()

    if fetch is None:
        return {k[0]: None for k in execute.description}

    return {k[0]: v for k, v in list(zip(execute.description, fetch))}

または

def select_column_and_value(self, sql, parameters=()):
    execute = self.execute(sql, parameters)
    fetch = execute.fetchone()

    if fetch is None:
        return {}

    return {k[0]: v for k, v in list(zip(execute.description, fetch))}

0
import sqlite3

db = sqlite3.connect('mydatabase.db')
cursor = db.execute('SELECT * FROM students ORDER BY CREATE_AT')
studentList = cursor.fetchall()

columnNames = list(map(lambda x: x[0], cursor.description)) #students table column names list
studentsAssoc = {} #Assoc format is dictionary similarly


#THIS IS ASSOC PROCESS
for lineNumber, student in enumerate(studentList):
    studentsAssoc[lineNumber] = {}

    for columnNumber, value in enumerate(student):
        studentsAssoc[lineNumber][columnNames[columnNumber]] = value


print(studentsAssoc)

結果は間違いなく本当ですが、私は最善を知りません。


0

Pythonの辞書は、要素への任意のアクセスを提供します。したがって、「名前」が付いた辞書は、一方では情報を提供している可能性がありますが(別名フィールド名)、不要なフィールドを「順序付け解除」します。

最善の方法は、別のリストで名前を取得し、必要に応じて自分で結果と組み合わせることです。

try:
         mycursor = self.memconn.cursor()
         mycursor.execute('''SELECT * FROM maintbl;''')
         #first get the names, because they will be lost after retrieval of rows
         names = list(map(lambda x: x[0], mycursor.description))
         manyrows = mycursor.fetchall()

         return manyrows, names

また、すべてのアプローチで、名前はクエリで指定した名前であり、データベース内の名前ではないことも覚えておいてください。例外はSELECT * FROM

辞書を使用して結果を取得することが唯一の懸念事項である場合は、必ずconn.row_factory = sqlite3.Row(別の回答で既に述べられている)を使用してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.