web-dev-qa-db-fra.com

Faire une liste de dictionnaires avec cx_Oracle

J'utilise la fonction suivante pour créer un format "plus lisible" (supposé) pour récupérer des données à partir d'Oracle. Voici la fonction:

def rows_to_dict_list(cursor):
    """ 
    Create a list, each item contains a dictionary outlined like so:
    { "col1_name" : col1_data }
    Each item in the list is technically one row of data with named columns,
    represented as a dictionary object
    For example:
    list = [
        {"col1":1234567, "col2":1234, "col3":123456, "col4":BLAH},
        {"col1":7654321, "col2":1234, "col3":123456, "col4":BLAH}
    ]
    """

    # Get all the column names of the query.
    # Each column name corresponds to the row index
    # 
    # cursor.description returns a list of tuples, 
    # with the 0th item in the Tuple being the actual column name.
    # everything after i[0] is just misc Oracle info (e.g. datatype, size)
    columns = [i[0] for i in cursor.description]

    new_list = []
    for row in cursor:
        row_dict = dict()
        for col in columns:
            # Create a new dictionary with field names as the key, 
            # row data as the value.
            #
            # Then add this dictionary to the new_list
            row_dict[col] = row[columns.index(col)]

        new_list.append(row_dict)
    return new_list

J'utiliserais alors la fonction comme ceci:

sql = "Some kind of SQL statement"
curs.execute(sql)
data = rows_to_dict_list(curs)
#
for row in data:
    item1 = row["col1"]
    item2 = row["col2"]
    # Do stuff with item1, item2, etc...
    # You don't necessarily have to assign them to variables,
    # but you get the idea.

Bien que cela semble fonctionner assez bien avec différents niveaux de stress, je me demande s’il existe un moyen plus efficace ou «pythonique» de procéder.

18
Nitzle

Il y a d'autres améliorations à faire, mais cela m'a vraiment frappé:

    for col in columns:
        # Create a new dictionary with field names as the key, 
        # row data as the value.
        #
        # Then add this dictionary to the new_list
        row_dict[col] = row[columns.index(col)]

En plus d'être inefficace, utiliser index dans des situations comme celle-ci est sujet à des bogues, du moins dans les situations où le même élément peut apparaître deux fois dans une liste. Utilisez enumerate à la place:

    for i, col in enumerate(columns):
        # Create a new dictionary with field names as the key, 
        # row data as the value.
        #
        # Then add this dictionary to the new_list
        row_dict[col] = row[i]

Mais ce sont de petites pommes de terre, vraiment. Voici une version beaucoup plus compacte de cette fonction:

def rows_to_dict_list(cursor):
    columns = [i[0] for i in cursor.description]
    return [dict(Zip(columns, row)) for row in cursor]

Faites-moi savoir si cela fonctionne.

25
senderle

Pour éviter de gaspiller tout le contenu d'une liste dès le départ, vous pouvez envelopper le curseur dans une fonction de générateur:

def rows_as_dicts(cursor):
    """ returns cx_Oracle rows as dicts """
    colnames = [i[0] for i in cursor.description]
    for row in cursor:
        yield dict(Zip(colnames, row))

Puis utilisez comme suit - les lignes du curseur sont converties en dict lors de l'itération:

for row in rows_as_dicts(cursor):
    item1 = row["col1"]
    item2 = row["col2"]
10
Josh Werts

N'utilisez pas dict pour les grands ensembles de résultats, car l'utilisation de la mémoire sera énorme. J'utilise beaucoup cx_Oracle et je n'ai pas de curseur de dictionnaire sympa qui me gêne suffisamment pour écrire un module à cette fin. Je dois également connecter Python à de nombreuses bases de données différentes. Je l'ai donc utilisé d'une manière que vous pouvez utiliser avec n'importe quel connecteur DB API 2.

C'est sur PyPi SGBD - Des bases de données simplifiées

>>> import dbms
>>> db = dbms.OraConnect('myUser', 'myPass', 'myInstance')
>>> cur = db.cursor()
>>> cur.execute('SELECT * FROM people WHERE id = :id', {'id': 1123})
>>> row = cur.fetchone()
>>> row['last_name']
Bailey
>>> row.last_name
Bailey
>>> row[3]
Bailey
>>> row[0:4]
[1123, 'Scott', 'R', 'Bailey']
4
Scott Bailey

Supposons que le curseur "Cursor" est déjà défini et prêt à disparaître:

byCol = {cl:i for i,(cl,type, a, b, c,d,e) in enumerate(Cursor.description)}

alors vous pouvez simplement aller:

for row in Cursor: column_of_interest = row[byCol["COLUMN_NAME_OF_INTEREST"]]

Pas aussi propre et lisse que si le système s'en occupait tout seul, mais pas si horrible.

0
The Nate

Créer un dict

cols=dict()
for col, desc in enumerate(cur.description):
    cols[desc[0]] = col

Accéder:

for result in cur
    print (result[cols['COL_NAME']])
0
jdex

J'en ai un meilleur:

import cx_Oracle

def makedict(cursor):
"""Convert cx_Oracle query result to be a dictionary   
"""
cols = [d[0] for d in cursor.description]

def createrow(*args):
    return dict(Zip(cols, args))

return createrow

db = cx_Oracle.connect('user', 'pw', 'Host')
cursor = db.cursor()
rs = cursor.execute('SELECT * FROM Tablename')
cursor.rowfactory = makedict(cursor)
0
YellowTree