web-dev-qa-db-ja.com

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

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'}

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

93
Meloun

ドキュメントの例のように、 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ベースのソリューションよりも優れているでしょう。

137
Alex Martelli

Adam Schmidegの回答とAlex Martelliの回答の両方でその答えが部分的に言及されていても、この質問に答えると思いました。同じ質問をしている私のような他の人のために、答えを簡単に見つけるために。

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
20
gandalf

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

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

これを乗り越えるために、行を取得して辞書に変換するヘルパー関数を使用します。これは、辞書オブジェクトがRowオブジェクトよりも望ましい場合にのみ使用します(たとえば、Rowオブジェクトが辞書APIもネイティブにサポートしていない文字列フォーマットなどの場合)。ただし、他の場合は常にRowオブジェクトを使用します。

def dict_from_row(row):
    return dict(Zip(row.keys(), row))       
19
bbengfort

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.

ええ、自分でやってください。

短いバージョン:

db.row_factory = lambda c, r: dict([(col[0], r[idx]) for idx, col in enumerate(c.description)])
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)

あなたが決める :)

2
Ran Aroussi

SQLiteに接続したら、con = sqlite3.connect(.....)を実行するだけで十分です。

con.row_factory = sqlite3.Row

出来上がり!

1

前述のソリューションに似ていますが、最もコンパクトです:

db.row_factory = lambda C, R: { c[0]: R[i] for i, c in enumerate(C.description) }
1
Falko
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
Emrah Tuncel

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(別の回答で既に述べられている)。

0
ilias iliadis

または、次のように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
andere

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
Macabeus