SQLalchemy rowcount sempre -1 para instruções
Eu estava brincando com o SQLalchemy e o Microsoft SQL Server para pegar o jeito das funções quando me deparei com um comportamento estranho. Fui ensinado que o atributo rowcount no objeto proxy de resultado dirá quantas linhas foram afetadas pela execução de uma instrução. No entanto, quando seleciono ou insiro uma ou várias linhas em meu banco de dados de teste, sempre obtenho -1. Como pode ser isso e como posso corrigir isso para refletir a realidade?
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)
A função de impressão para cada bloco executado separadamente, o código de exemplo imprime -1. O Ex1 obtém com êxito todas as linhas e ambas as instruções de inserção gravam os dados com êxito no banco de dados.
De acordo com o seguinte problema, o atributo rowcount nem sempre é confiável. Isso também é verdade aqui? E quando, como posso compensar com uma instrução Count em uma transação SQLalcehmy? PDO :: rowCount () retornando -1
Respostas
A linha única INSERT … VALUES ( … )é trivial: se a instrução for bem-sucedida, uma linha foi afetada e, se falhar (gerar um erro), nenhuma linha foi afetada.
Para uma multi-linha, INSERTbasta executá-la dentro de uma transação e reverter se ocorrer um erro. Então, o número de linhas afetadas será zero ou len(values_list).
Para obter o número de linhas que um SELECT irá retornar, enrole a consulta de seleção em uma SELECT count(*)consulta e executar esse primeiro, por exemplo:
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)