Як я можу отримати малюнок із запиту sqlite?


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 року. Питання, з яким ви пов’язані, - це листопад 2010 року. Отже, це дура. І як можна було б очікувати, зворотний коментар був зроблений на той :-)
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.Rowі я спробував, connection.row_factory = dict_factoryяк показано, але cur.fetchall()все ще дає мені список кортежів - будь-яка ідея, чому це не працює?
displayname

@displayname, чи не в документації зазначено "Він намагається імітувати кортеж у більшості своїх функцій." Я майже впевнений, що якимось чином схожий на те, що ви можете отримати collections.namedtuple. Під час використання cur.fetchmany()я отримую записи на зразок <sqlite3.Row object at 0x...>.
оні

Навіть через 7 років ця відповідь є найбільш корисною копією та вставкою з документів, які я знайшов у програмі SO. Дякую!
WillardSolutions

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()].
Гонсало Рібейро

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


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?
Ядерний

@ user1123466: ... Як і між SQLite, MySQL, Postgres, Oracle, MS SQL Server, Firebird ...
Ignacio Vazquez-Abrams


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)

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)

Тобі вирішувати :)


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
Філліп

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.Розводити в словник наступним чином. Це дасть словник зі списком для кожного рядка.

    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(вже сказано в іншій відповіді).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.