web-dev-qa-db-fra.com

MySQL: obtient le nom de la colonne ou l'alias de la requête

Je ne demande pas la commande SHOW COLUMNS.

Je souhaite créer une application qui fonctionne de la même manière que heidisql, dans laquelle vous pouvez spécifier une requête SQL et, une fois exécutée, renvoie un jeu de résultats avec des lignes et des colonnes représentant le résultat de votre requête. Les noms de colonne dans le jeu de résultats doivent correspondre aux colonnes sélectionnées, telles que définies dans votre requête SQL.

Dans mon programme Python (en utilisant MySQLdb), ma requête renvoie uniquement les résultats des lignes et des colonnes, mais pas les noms de colonne. Dans l'exemple suivant, les noms de colonne seraient ext, totalsize et filecount. Le code SQL serait éventuellement externe au programme. 

Le seul moyen que je puisse comprendre pour que cela fonctionne est d'écrire ma propre logique d'analyse SQL pour extraire les noms de colonne sélectionnés.

Existe-t-il un moyen simple d’obtenir les noms de colonne pour le code SQL fourni? Ensuite, j’ai besoin de savoir combien de colonnes la requête renvoie-t-elle?

# Python

import MySQLdb

#===================================================================
# connect to mysql
#===================================================================

try:
    db = MySQLdb.connect(Host="myhost", user="myuser", passwd="mypass",db="mydb")
except MySQLdb.Error, e:
    print "Error %d: %s" % (e.args[0], e.args[1])
    sys.exit (1)

#===================================================================
# query select from table
#===================================================================

cursor = db.cursor ()   

cursor.execute ("""\
     select ext,
        sum(size) as totalsize,
        count(*) as filecount
     from fileindex
    group by ext
    order by totalsize desc;
""")

while (1):
    row = cursor.fetchone ()
    if row == None:
        break
    print "%s %s %s\n" % (row[0], row[1], row[2])

cursor.close()
db.close()      
47
panofish

curseur.description vous donnera un nuplet de nuplets où [0] pour chacun est l'en-tête de colonne.

num_fields = len(cursor.description)
field_names = [i[0] for i in cursor.description]
183
user625477

C’est la même chose que thefreeman mais plus de façon pythonique en utilisant la compréhension des listes et des dictionnaires 

columns = cursor.description 
result = [{columns[index][0]:column for index, column in enumerate(value)} for value in cursor.fetchall()]

pprint.pprint(result)
22
James

Semblable à la réponse @James, une manière plus pythonique peut être:

fields = map(lambda x:x[0], cursor.description)
result = [dict(Zip(fields,row))   for row in cursor.fetchall()]

Vous pouvez obtenir une seule colonne avec map sur le résultat:

extensions = map(lambda x: x['ext'], result)

ou filtrer les résultats:

filter(lambda x: x['filesize'] > 1024 and x['filesize'] < 4096, result)

ou accumuler des valeurs pour les colonnes filtrées:

totalTxtSize = reduce(
        lambda x,y: x+y,
        filter(lambda x: x['ext'].lower() == 'txt', result)
)
10
juandesant

Je pense que cela devrait faire ce dont vous avez besoin (repose sur la réponse ci-dessus). Je suis sûr qu'il y a une manière plus pythonique de l'écrire, mais vous devriez en avoir une idée générale.

cursor.execute(query)
columns = cursor.description
result = []
for value in cursor.fetchall():
    tmp = {}
    for (index,column) in enumerate(value):
        tmp[columns[index][0]] = column
    result.append(tmp)
pprint.pprint(result)
7
thefreeman

Vous pouvez également utiliser MySQLdb.cursors.DictCursor. Cela transforme votre jeu de résultats en une liste python de dictionnaires python, bien qu'il utilise un curseur spécial, donc techniquement moins portable que la réponse acceptée. Pas sûr de la vitesse. Voici le code original édité qui utilise cela.

#!/usr/bin/python -u

import MySQLdb
import MySQLdb.cursors

#===================================================================
# connect to mysql
#===================================================================

try:
    db = MySQLdb.connect(Host='myhost', user='myuser', passwd='mypass', db='mydb', cursorclass=MySQLdb.cursors.DictCursor)
except MySQLdb.Error, e:
    print 'Error %d: %s' % (e.args[0], e.args[1])
    sys.exit(1)

#===================================================================
# query select from table
#===================================================================

cursor = db.cursor()

sql = 'SELECT ext, SUM(size) AS totalsize, COUNT(*) AS filecount FROM fileindex GROUP BY ext ORDER BY totalsize DESC;'

cursor.execute(sql)
all_rows = cursor.fetchall()

print len(all_rows) # How many rows are returned.
for row in all_rows: # While loops always make me shudder!
    print '%s %s %s\n' % (row['ext'], row['totalsize'], row['filecount'])

cursor.close()
db.close()  

Les fonctions de dictionnaire standard s'appliquent, par exemple, len(row[0]) pour compter le nombre de colonnes de la première ligne, list(row[0]) pour une liste de noms de colonnes (pour la première ligne), etc. J'espère que cela vous aidera!

4
Eugene

On dirait que MySQLdb ne fournit pas de traduction pour cet appel API. L’appel C API approprié est mysql_fetch_fields , et il n’ya pas de traduction MySQLdb pour cela

2
Daniel DiPaolo

Essayer:

cursor.column_names

version du connecteur mysql:

mysql.connector.__version__
'2.2.9'
1
Amin

Ceci n'est qu'un ajout à la réponse acceptée:

def get_results(db_cursor):
    desc = [d[0] for d in db_cursor.description]
    results = [dotdict(dict(Zip(desc, res))) for res in db_cursor.fetchall()]
    return results

dotdict est:

class dotdict(dict):
    __getattr__ = dict.get
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

Cela vous permettra d'accéder beaucoup plus facilement aux valeurs par noms de colonnes.
Supposons que vous avez une table user avec les colonnes name et email:

cursor.execute('select * from users')
results = get_results(cursor)
for res in results:
  print(res.name, res.email)
0
MikeL