SQLalchemy rowcount toujours -1 pour les instructions

Nov 16 2020

Je jouais avec SQLalchemy et Microsoft SQL Server pour comprendre les fonctions lorsque je suis tombé sur un comportement étrange. On m'a appris que l'attribut rowcount sur l'objet proxy de résultat indiquera combien de lignes ont été affectées par l'exécution d'une instruction. Cependant, lorsque je sélectionne ou insère une ou plusieurs lignes dans ma base de données de test, j'obtiens toujours -1. Comment est-ce possible et comment puis-je résoudre ce problème pour refléter la réalité?

connection = engine.connect()
metadata = MetaData()

# Ex1: select statement for all values
student = Table('student', metadata, autoload=True, autoload_with=engine)
stmt = select([student])
result_proxy = connection.execute(stmt)
results = result_proxy.fetchall()
print(result_proxy.rowcount)

# Ex2: inserting single values
stmt = insert(student).values(firstname='Severus', lastname='Snape')
result_proxy = connection.execute(stmt)
print(result_proxy.rowcout)
 
# Ex3: inserting multiple values 
stmt = insert(student)
values_list = [{'firstname': 'Rubius', 'lastname': 'Hagrid'},
               {'firstname': 'Minerva', 'lastname': 'McGonogall'}]
result_proxy = connection.execute(stmt, values_list)
print(result_proxy.rowcount)

La fonction d'impression pour chaque bloc d'exemple de code exécuté séparément imprime -1. L'ex1 récupère avec succès toutes les lignes et les deux instructions d'insertion écrivent avec succès les données dans la base de données.

Selon le problème suivant, l'attribut rowcount n'est pas toujours fiable. Est-ce vrai ici aussi? Et quand, comment puis-je compenser avec une instruction Count dans une transaction SQLalcehmy? PDO :: rowCount () retournant -1

Réponses

1 GordThompson Nov 19 2020 at 02:46

La ligne unique INSERT … VALUES ( … )est triviale: si l'instruction réussit, une ligne a été affectée, et si elle échoue (génère une erreur), aucune ligne n'a été affectée.

Pour une ligne à plusieurs lignes, INSERTexécutez -la simplement dans une transaction et annulez-la si une erreur se produit. Ensuite, le nombre de lignes affectées sera soit zéro soit len(values_list).

Pour obtenir le nombre de lignes qu'un SELECT va revenir, enveloppez la requête de sélection dans une SELECT count(*)requête et exécuter cette première, par exemple:

select_stmt = sa.select([Parent])
count_stmt = sa.select([sa.func.count(sa.text("*"))]).select_from(
    select_stmt.alias("s")
)
with engine.connect() as conn:
    conn.execution_options(isolation_level="SERIALIZABLE")
    rows_found = conn.execute(count_stmt).scalar()
    print(f"{rows_found} row(s) found")
    results = conn.execute(select_stmt).fetchall()
for item in results:
    print(item.id)