web-dev-qa-db-fra.com

Passer la liste des paramètres à SQL dans psycopg2

J'ai une liste d'ID de lignes à récupérer dans la base de données. J'utilise python et psycopg2, et mon problème est de savoir comment passer efficacement ces identifiants à SQL? Je veux dire que si je connais la longueur de cette liste, c'est assez facile car je peux toujours ajouter manuellement ou automatiquement autant d'expressions "% s" dans la chaîne de requête que nécessaire, mais ici je ne sais pas de combien j'ai besoin. Il est important que je doive sélectionner ces lignes en utilisant sql "id IN (id1, id2 , ...) ". Je sais qu'il est possible de vérifier la longueur de la liste et de concaténer le nombre approprié de"% s "dans la chaîne de requête, mais je crains que ce ne soit très lent et laid. Est-ce que quelqu'un vous avez une idée sur la façon de le résoudre? Et s'il vous plaît ne demandez pas pourquoi je dois le faire avec la déclaration "IN" - c'est une référence qui fait partie de mon devoir de classe. Merci d'avance!

44
k_wisniewski

Les tuples Python sont convertis en listes SQL dans psycopg2:

cur.mogrify("SELECT * FROM table WHERE column IN %s;", ((1,2,3),))

sortirait

'SELECT * FROM table WHERE column IN (1,2,3);'

Pour Python nouveaux arrivants: il est malheureusement important d'utiliser un Tuple, pas une liste ici. Voici un deuxième exemple:

cur.mogrify("SELECT * FROM table WHERE column IN %s;", 
    Tuple([row[0] for row in rows]))
71
philofinfinitejest

cette question est ancienne et peut-être il y en a une plus récente, mais la réponse que mes collègues proposent en ce moment est la suivante:

sql = "SELECT * FROM table WHERE column = ANY(%(parameter_array)s)"
cur.execute(sql,{"parameter_array": [1, 2, 3]})
2
Brandon Henry

Maintenant, le module sql de psycopg2 ( https://www.psycopg.org/docs/sql.html ) peut être utilisé pour se protéger contre les erreurs et les injections, comme par exemple:

import psycopg2
from psycopg2 import sql

params = config()
conn = psycopg2.connect(**params)
cur = conn.cursor()

ids = ['a','b','c']
sql_query = sql.SQL('SELECT * FROM {} WHERE id IN ({});').format(
                    sql.Identifier('table_name'),
                    sql.SQL(',').join(map(sql.Identifier, ids))
                )
print (sql_query.as_string(cur)) # for debug
cur.execute(sql_query)

from configparser import ConfigParser
def config(filename='database.ini', section='postgresql'):
    # create a parser
    parser = ConfigParser()
    # read config file
    parser.read(filename)

    # get section, default to postgresql
    db = {}
    if parser.has_section(section):
        params = parser.items(section)
        for param in params:
            db[param[0]] = param[1]
    else:
        raise Exception('Section {0} not found in the {1} file'.format(section, filename))

    return db

Remarque: sql.Identifier ajoutera des guillemets si nécessaire, donc cela fonctionnera si vous utilisez également des identifiants entre guillemets dans PostgreSQL (ils doivent être utilisés pour autoriser, par exemple, des noms sensibles à la casse).

Exemple et structure de database.ini:

[postgresql]
Host=localhost
port=5432
database=postgres
user=user
password=mypass
2
Alexei Martianov