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 월입니다. 그리고 예상대로 반대 의견이 그 하나에
달렸습니다.

답변:


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 유형으로 설정하는 것을 고려해야합니다. Row는 거의 메모리 오버 헤드없이 열에 대한 인덱스 기반 및 대소 문자를 구분하지 않는 이름 기반 액세스를 모두 제공합니다. 사용자 정의 사전 기반 접근 방식이나 심지어 db_row 기반 솔루션보다 낫습니다.


SELECT 1 AS "dog[cat]"를 들어 열 이름에 특수 문자 cursor가있는 경우 딕셔너리를 생성 할 올바른 설명이 없습니다.
Crazometer

나는 설정 connection.row_factory = sqlite3.Row하고 connection.row_factory = dict_factory표시된대로 시도 했지만 cur.fetchall()여전히 튜플 목록을 제공하고 있습니다. 왜 이것이 작동하지 않는지 아십니까?
displayname

@displayname은 문서에 "대부분의 기능에서 튜플을 모방하려고합니다."라고 언급하지 않습니다. 나는 그것이 당신이 얻을 수있는 것과 어떻게 든 비슷하다고 확신합니다 collections.namedtuple. 내가 사용할 때 나는 cur.fetchmany()같은 항목을 얻습니다 <sqlite3.Row object at 0x...>.
ony

7 년 후에도이 답변은 내가 찾은 문서에서 가장 유용한 복사 및 붙여 넣기입니다. 감사!
WillardSolutions jul.

40

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

21
현재 fetchall()sqlite3.Row개체 를 반환하는 것으로 보입니다 . 그러나 이들은 단순히 사용하여 사전으로 변환 할 수 있습니다 dict(): result = [dict(row) for row in c.fetchall()].
Gonçalo Ribeiro

21

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))       

9
sqlite3.Row는 매핑 프로토콜을 구현합니다. 당신은 할 수print "%(id)i - %(name)s: %(value)s" % dict(row)
Mzzzzzz

9

SQLite에 연결 한 후 : con = sqlite3.connect(.....)다음을 실행하는 것으로 충분합니다.

con.row_factory = sqlite3.Row

짜잔!


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은, 포스트 그레스, 오라클, MS SQL 서버, 파이어 버드 사이 ...처럼 ...
이그나시오 바스케스 - 에이 브람스

3

더 짧은 버전 :

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

@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

앞서 언급 한 솔루션과 유사하지만 가장 간결합니다.

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

나는 당신이 올바른 길을 가고 있다고 생각합니다. 이 작업을 매우 간단하게 유지하고하려는 작업을 완료하겠습니다.

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

세 줄만 사용하는 일반적인 대안

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.