Подтвердить что ты не робот

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

Как выполнить сериализацию вывода курсора pyodbc (от .fetchone, .fetchmany или .fetchall) в качестве словаря Python?

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

@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()]}

Ответ 3

Вот краткая версия, которую вы могли бы использовать

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

Ответ 4

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

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

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

;)

Ответ 5

Мне нравятся ответы @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 для этого.

Ответ 6

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

    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

Ответ 7

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

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()), но вы получите эту идею. Более поздний пример был бы полезен, если не извлекать все данные, кроме одной строки за раз, например:

Использование 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]]

Ответ 8

Для ситуаций, когда курсор недоступен - например, когда строки были возвращены каким-либо вызовом функции или внутренним методом, вы все равно можете создать словарное представление, используя row.cursor_description

def row_to_dict(row):
    return dict(zip([t[0] for t in row.cursor_description], row))