Вывод результатов курсора pyodbc в виде словаря python

как сериализовать вывод курсора pyodbc (из .fetchone, .fetchmany или .fetchall) как словарь Python?

Я использую bottlepy и должен вернуть dict, чтобы он мог вернуть его как JSON.

7 ответов


Если вы не знаете столбцы заранее, используйте курсор.описание чтобы создать список имен столбцов и zip С каждой строкой, чтобы создать список словарей. Пример предполагает, что соединение и запрос построены:

>>> cursor = connection.cursor().execute(sql)
>>> columns = [column[0] for column in cursor.description]
>>> print columns
['name', 'create_date']
>>> results = []
>>> for row in cursor.fetchall():
...     results.append(dict(zip(columns, row)))
...
>>> print results
[{'create_date': datetime.datetime(2003, 4, 8, 9, 13, 36, 390000), 'name': u'master'},   
 {'create_date': datetime.datetime(2013, 1, 30, 12, 31, 40, 340000), 'name': u'tempdb'},
 {'create_date': datetime.datetime(2003, 4, 8, 9, 13, 36, 390000), 'name': u'model'},     
 {'create_date': datetime.datetime(2010, 4, 2, 17, 35, 8, 970000), 'name': u'msdb'}]

используя результат @Beargle с bottlepy, я смог создать этот очень краткий запрос, раскрывающий конечную точку:

@route('/api/query/<query_str>')
def query(query_str):
    cursor.execute(query_str)
    return {'results':
            [dict(zip([column[0] for column in cursor.description], row))
             for row in cursor.fetchall()]}

вот краткая версия формы, которую вы можете использовать

>>> cursor.select("<your SQL here>")
>>> single_row = dict(zip(zip(*cursor.description)[0], cursor.fetchone()))
>>> multiple_rows = [dict(zip(zip(*cursor.description)[0], row)) for row in cursor.fetchall()]

как вы знаете, когда вы добавляете * в список, вы в основном удаляете список, оставляя отдельные записи списка в качестве параметров вызываемой функции. С помощью zip мы выбираем 1-й К N записи и застегнуть их вместе, как молния в вас брюки.

С помощью

zip(*[(a,1,2),(b,1,2)])
# interpreted by python as zip((a,1,2),(b,1,2))

вы получаете

[('a', 'b'), (1, 1), (2, 2)]

поскольку описание-это кортеж с кортежами, где каждый кортеж описывает заголовок и тип данных для каждого столбца, вы можете извлечь первый из каждого кортежа с

>>> columns = zip(*cursor.description)[0]

эквивалентно

>>> columns = [column[0] for column in cursor.description]

в основном выходя из @Torxed response, я создал полный обобщенный набор функций для поиска схемы и данных в словаре:

def schema_dict(cursor):
    cursor.execute("SELECT sys.objects.name, sys.columns.name FROM sys.objects INNER JOIN sys.columns ON sys.objects.object_id = sys.columns. object_id WHERE sys.objects.type = 'U';")
    schema = {}

    for it in cursor.fetchall():
        if it[0] not in schema:
            schema[it[0]]={'scheme':[]}
        else:
            schema[it[0]]['scheme'].append(it[1])

    return schema


def populate_dict(cursor, schema):
    for i in schema.keys():
        cursor.execute("select * from {table};".format(table=i))

        for row in cursor.fetchall():
            colindex = 0

            for col in schema[i]['scheme']:
                if not 'data' in schema[i]:
                    schema[i]['data']=[]

                schema[i]['data'].append(row[colindex])
                colindex += 1

    return schema

def database_to_dict():
    cursor = connect()
    schema = populate_dict(cursor, schema_dict(cursor))

Не стесняйтесь идти весь код-гольф на этом, чтобы уменьшить линии; но в то же время, это работает!

;)


Я знаю, что этот вопрос старый, но он помог мне понять, как сделать то, что мне нужно, что немного отличается от того, что просил ОП, поэтому я подумал, что поделюсь, чтобы помочь кому-то еще, что мне нужно: Если вы хотите полностью обобщить процедуру, которая выполняет запросы SQL Select, но вам нужно ссылаться на результаты по номеру индекса, а не по имени, вы можете сделать это со списком списков вместо словаря. Каждая строка возвращаемых данных представлена в возвращаемом списке в виде список значений полей (столбцов). Имена столбцов могут быть предоставлены в качестве первой записи возвращаемого списка, поэтому разбор возвращаемого списка в вызывающей процедуре может быть очень простым и гибким. Таким образом, процедура, выполняющая вызов базы данных, не должна ничего знать о данных, которые она обрабатывает. Вот такая рутина:

    def read_DB_Records(self, tablename, fieldlist, wherefield, wherevalue) -> list:

        DBfile = 'C:/DATA/MyDatabase.accdb'
        # this connection string is for Access 2007, 2010 or later .accdb files
        conn = pyodbc.connect(r'Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ='+DBfile)
        cursor = conn.cursor()

        # Build the SQL Query string using the passed-in field list:
        SQL = "SELECT "
        for i in range(0, len(fieldlist)):
            SQL = SQL + "[" + fieldlist[i] + "]"
            if i < (len(fieldlist)-1):
                SQL = SQL + ", "
        SQL = SQL + " FROM " + tablename

        # Support an optional WHERE clause:
        if wherefield != "" and wherevalue != "" :
            SQL = SQL + " WHERE [" + wherefield + "] = " + "'" + wherevalue + "';"

        results = []    # Create the results list object

        cursor.execute(SQL) # Execute the Query

        # (Optional) Get a list of the column names returned from the query:
        columns = [column[0] for column in cursor.description]
        results.append(columns) # append the column names to the return list

        # Now add each row as a list of column data to the results list
        for row in cursor.fetchall():   # iterate over the cursor
            results.append(list(row))   # add the row as a list to the list of lists

        cursor.close()  # close the cursor
        conn.close()    # close the DB connection

        return results  # return the list of lists

мне нравятся ответы @bryan и @foo-stack. Если вы работаете с postgresql и используете psycopg2 вы могли бы использовать некоторые лакомства от psycopg2 для достижения того же, указав cursorfactory быть DictCursor при создании курсора из соединения, например:

cur = conn.cursor( cursor_factory=psycopg2.extras.DictCursor )

Итак, теперь вы можете выполнить свой sql-запрос, и вы получите словарь для получения результатов, без необходимости отображать их вручную.

cur.execute( sql_query )
results = cur.fetchall()

for row in results:
    print row['row_no']

пожалуйста обратите внимание, что вам придется import psycopg2.extras чтобы это сработало.


предполагая, что вы знаете имена столбцов! Кроме того, вот три различных решения,
вы, наверное, хотите посмотреть на последний!

colnames = ['city', 'area', 'street']
data = {}

counter = 0
for row in x.fetchall():
    if not counter in data:
        data[counter] = {}

    colcounter = 0
    for colname in colnames:
        data[counter][colname] = row[colcounter]
        colcounter += 1

    counter += 1

это проиндексированных версия, не самое красивое решение, но оно будет работать. Другой способ-индексировать имя столбца как ключ словаря со списком внутри каждого ключа, содержащего данные в порядке номера строки. делая:

colnames = ['city', 'area', 'street']
data = {}

for row in x.fetchall():
    colindex = 0
    for col in colnames:
        if not col in data:
            data[col] = []
        data[col].append(row[colindex])
        colindex += 1

пишу это, я понимаю, что делаю for col in colnames можно заменить на for colindex in range(0, len()) но вы получить идею. Более поздний пример tho был бы полезен при извлечении не всех данных, а одной строки за раз, например:

использование dict для каждой строки данных

def fetchone_dict(stuff):
    colnames = ['city', 'area', 'street']
    data = {}

    for colindex in range(0, colnames):
        data[colnames[colindex]] = stuff[colindex]
    return data

row = x.fetchone()
print fetchone_dict(row)['city']

получение табличных имен (я думаю.. благодаря Foo Stack):
более прямое решение из beargle ниже!

cursor.execute("SELECT sys.objects.name, sys.columns.name FROM sys.objects INNER JOIN sys.columns ON sys.objects.object_id = sys.columns. object_id WHERE sys.objects.type = 'U';")
schema = {}
for it in cursor.fetchall():
    if it[0] in schema:
       schema[it[0]].append(it[1])
    else:
        schema[it[0]] = [it[1]]