Sqlite sorgusundan nasıl dikte alabilirim?


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

Yinelemeyle satırlara karşılık gelen listeler alıyorum.

for row in res:
    print row

Sütunların adını alabilirim

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

Ancak liste yerine sözlükler almak için bir işlev veya ortam var mı?

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

yoksa kendim mi yapmalıyım?



3
@ vy32: Bu soru Temmuz 2010'a aittir, bağlantı kurduğunuz soru Kasım 2010'dur. Demek ki dupe budur. Ve tahmin edileceği gibi, bunun üzerine ters yorum yapıldı :-)
aneroid

Yanıtlar:


159

Dokümanlardaki örnekte olduğu gibi row_factory kullanabilirsiniz :

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"]

veya belgelerde bu örnekten hemen sonra verilen tavsiyelere uyun:

Bir demet döndürmek yeterli değilse ve sütunlara isme dayalı erişim istiyorsanız, row_factory'yi yüksek düzeyde optimize edilmiş sqlite3.Row türüne ayarlamayı düşünmelisiniz. Row, neredeyse hiç bellek ek yükü olmadan sütunlara hem dizin tabanlı hem de büyük / küçük harfe duyarlı olmayan ad tabanlı erişim sağlar. Muhtemelen kendi özel sözlük tabanlı yaklaşımınızdan veya hatta db_row tabanlı bir çözümden daha iyi olacaktır.


Sütun adlarınızda özel karakterler varsa, örneğin SELECT 1 AS "dog[cat]", cursorbir dikt oluşturmak için doğru açıklamaya sahip olmayacaktır.
Crazometer

Ayarladım connection.row_factory = sqlite3.Rowve connection.row_factory = dict_factorygösterildiği gibi denedim ama cur.fetchall()hala bana bir tuple listesi veriyor - bunun neden çalışmadığına dair bir fikriniz var mı?
ekran adı

@displayname, dokümantasyonda "Özelliklerinin çoğunda bir tuple'ı taklit etmeye çalışır." Eminim ki bir şekilde alabileceğinize benzer collections.namedtuple. Kullandığım zaman cur.fetchmany()gibi girişler alıyorum <sqlite3.Row object at 0x...>.
ony

7 yıl sonra bile, bu yanıt, SO'da bulduğum belgelerden en yararlı kopyalayıp yapıştırmadır. Teşekkürler!
WillardSolutions

41

Hem Adam Schmideg'in hem de Alex Martelli'nin cevaplarında kısmen cevap verilmiş olsa da bu soruyu cevapladığımı düşündüm. Benim gibi aynı soruyu soranların cevabı kolayca bulması için.

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
Şu anda nesneleri döndürüyor fetchall()gibi görünüyor sqlite3.Row. Ancak bu sadece kullanarak bir sözlüğe dönüştürülmüş olabilir dict(): result = [dict(row) for row in c.fetchall()].
Gonçalo Ribeiro

21

Sqlite3.Row sınıfını kullansanız bile - hala aşağıdaki biçimde dize biçimlendirmesini kullanamazsınız:

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

Bunu aşmak için satırı alan ve bir sözlüğe dönüştüren bir yardımcı işlev kullanıyorum. Bunu yalnızca sözlük nesnesi Row nesnesine tercih edildiğinde kullanıyorum (örneğin, Row nesnesinin sözlük API'sini doğal olarak desteklemediği dize biçimlendirme gibi şeyler için). Ancak diğer zamanlarda Row nesnesini kullanın.

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

9
sqlite3.Row, haritalama protokolünü uygular. Yapabilirsinprint "%(id)i - %(name)s: %(value)s" % dict(row)
Mzzzzzz

9

SQLite'a bağlandıktan sonra: con = sqlite3.connect(.....)aşağıdakileri çalıştırmak yeterlidir:

con.row_factory = sqlite3.Row

İşte bu kadar!


8

Gönderen 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.

Yani evet, kendin yap.


> veritabanları arasında değişiklik gösterir - örneğin, sqlite 3.7 ve 3.8?
Nucular

@ user1123466: ... SQLite, MySQL, Postgres, Oracle, MS SQL Server, Firebird arasında olduğu gibi ...
Ignacio Vazquez-Abrams

3

Daha kısa versiyon:

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

3

Testlerimde en hızlı:

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)

vs:

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)

Sen karar ver :)


2

@ Gandalf'ın cevabında belirtildiği gibi, birinin kullanılması gerekir conn.row_factory = sqlite3.Row, ancak sonuçlar doğrudan sözlük değildir . dictSon döngüde ek bir "cast" eklemek gerekir :

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

Daha önce bahsedilen çözümlere benzer, ancak en kompakt:

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

Bu benim için çalıştı, yukarıdaki cevap db.row_factory = sqlite3.Rowbenim için işe yaramadı (bir JSON TypeError ile sonuçlandığından)
Phillip

1

Bence doğru yoldaydın. Bunu çok basit tutalım ve yapmaya çalıştığınız şeyi tamamlayalım:

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)

Dezavantajı,.fetchall() masanız çok büyükse hafıza tüketiminizi öldüren şeydir . Ancak birkaç bin metin satırı ve sayısal sütunla uğraşan önemsiz uygulamalar için bu basit yaklaşım yeterince iyidir.

Ciddi konular için, diğer birçok cevapta önerildiği gibi sıra fabrikalara bakmalısınız.


0

Veya sqlite3.Rows'u aşağıdaki gibi bir sözlüğe dönüştürebilirsiniz. Bu, her satır için bir liste içeren bir sözlük verecektir.

    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

Yalnızca üç satır kullanan genel bir alternatif

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

Ancak sorgunuz hiçbir şey döndürmezse, hatayla sonuçlanır. Bu durumda...

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

veya

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)

Sonuç kesinlikle doğru, ancak en iyisini bilmiyorum.


0

Python'daki sözlükler, öğelerine keyfi erişim sağlar. Dolayısıyla, "adlar" içeren herhangi bir sözlük, bir yandan bilgilendirici olsa da (diğer bir deyişle alan adları nelerdir), istenmeyen olabilecek alanların "sırasını kaldırır".

En iyi yaklaşım, isimleri ayrı bir listede almak ve gerekirse bunları sonuçlarla kendi başınıza birleştirmektir.

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

Ayrıca, tüm yaklaşımlarda adların veritabanındaki adlar değil, sorguda sağladığınız adlar olduğunu unutmayın. İstisna,SELECT * FROM

Tek endişeniz sonuçları bir sözlük kullanarak almaksa, o zaman kesinlikle kullanın conn.row_factory = sqlite3.Row(başka bir cevapta belirtilmiştir).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.