Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

1.4K
Views
¿Forma sugerida de ejecutar múltiples declaraciones sql en python?

¿Cuál sería la forma sugerida de ejecutar algo como lo siguiente en python:

 self.cursor.execute('SET FOREIGN_KEY_CHECKS=0; DROP TABLE IF EXISTS %s; SET FOREIGN_KEY_CHECKS=1' % (table_name,))

Por ejemplo, ¿deberían ser tres self.cursor.execute(...) separadas? ¿Hay algún método específico que deba usarse además de cursor.execute(...) para hacer algo como esto, o cuál es la práctica sugerida para hacer esto? Actualmente el código que tengo es el siguiente:

 self.cursor.execute('SET FOREIGN_KEY_CHECKS=0;') self.cursor.execute('DROP TABLE IF EXISTS %s;' % (table_name,)) self.cursor.execute('SET FOREIGN_KEY_CHECKS=1;') self.cursor.execute('CREATE TABLE %s select * from mytable;' % (table_name,))

Como puede ver, todo se ejecuta por separado... así que no estoy seguro de si es una buena idea o no (o más bien, cuál es la mejor manera de hacer lo anterior). ¿Quizás BEGIN...END ?

over 4 years ago · Santiago Trujillo
8 answers
Answer question

0

En la documentación de MySQLCursor.execute() , sugieren usar el parámetro multi=True :

 operation = 'SELECT 1; INSERT INTO t1 VALUES (); SELECT 2' for result in cursor.execute(operation, multi=True): ...

Puede encontrar otro ejemplo en el código fuente del módulo.

over 4 years ago · Santiago Trujillo Report

0

Me atasqué varias veces en este tipo de problemas en el proyecto. Después de mucha investigación, encontré algunos puntos y sugerencias.

  1. El método execute() funciona bien con una consulta a la vez. Porque durante el método de ejecución cuida el estado.

Sé que cursor.execute(operation, params=None, multi=True) toma múltiples consultas. Pero los parámetros no funcionan bien en este caso y, a veces, la excepción de error interno también estropea todos los resultados. Y el código se vuelve masivo y ambiguo. Incluso los documentos también mencionan esto. ingrese la descripción de la imagen aquí

  1. executemany(operation, seq_of_params) no es una buena práctica para implementar cada vez. Porque la operación que produce uno o más conjuntos de resultados constituye un comportamiento indefinido, y se permite (pero no se requiere) que la implementación genere una excepción cuando detecta que se ha creado un conjunto de resultados mediante una invocación de la operación. [fuente - documentos]

Sugerencia 1-:

Haga una lista de consultas como -:

 table_name = 'test' quries = [ 'SET FOREIGN_KEY_CHECKS=0;', 'DROP TABLE IF EXISTS {};'.format(table_name), 'SET FOREIGN_KEY_CHECKS=1;', 'CREATE TABLE {} select * from mytable;'.format(table_name), ] for query in quries: result = self.cursor.execute(query) # Do operation with result

Sugerencia 2-:

Establecer con dict. [you can also make this by executemany for recursive parameters for some special cases.]

 quries = [ {'DROP TABLE IF EXISTS %(table_name);':{'table_name': 'student'}}, {'CREATE TABLE %(table_name) select * from mytable;': {'table_name':'teacher'}}, {'SET FOREIGN_KEY_CHECKS=0;': ''} ] for data in quries: for query, parameter in data.iteritems(): if parameter == '': result = self.cursor.execute(query) # Do something with result else: result = self.cursor.execute(query, parameter) # Do something with result

También puede usar dividir con script. Not recommended

 with connection.cursor() as cursor: for statement in script.split(';'): if len(statement) > 0: cursor.execute(statement + ';')

Nota: utilizo principalmente la list of query , pero en algún lugar complejo uso el enfoque de dictionary .

over 4 years ago · Santiago Trujillo Report

0

Mire la documentación de MySQLCursor.execute().

Afirma que puede pasar un parámetro multi que le permite ejecutar múltiples consultas en una cadena.

Si multi se establece en True, execute() puede ejecutar varias declaraciones especificadas en la cadena de operación.

multi es un segundo parámetro opcional para la llamada de ejecución ():


 operation = 'SELECT 1; INSERT INTO t1 VALUES (); SELECT 2' for result in cursor.execute(operation, multi=True):

over 4 years ago · Santiago Trujillo Report

0

Con import mysql.connector

puede hacer el siguiente comando, solo necesita reemplazar t1 y episodios, con sus propios tabaes

 tablename= "t1" mycursor.execute("SET FOREIGN_KEY_CHECKS=0; DROP TABLE IF EXISTS {}; SET FOREIGN_KEY_CHECKS=1;CREATE TABLE {} select * from episodes;".format(tablename, tablename),multi=True)

Mientras esto se ejecute, debe asegurarse de que las restricciones de clave externa que estarán vigentes después de habilitarlo no causen problemas.

si tablename es algo que un usuario puede ingresar, debe pensar en una lista blanca de nombres de tabla.

Las declaraciones preparadas no funcionan con nombres de tablas y columnas, por lo que tenemos que usar el reemplazo de cadenas para obtener los nombres de tabla correctos en la posición correcta, pero esto hará que su código sea vulnerable a la inyección de sql

El multi=True es necesario para ejecutar 4 comandos en el conector, cuando lo probé, el depurador lo exigió.

over 4 years ago · Santiago Trujillo Report

0

Todas las respuestas son completamente válidas, por lo que agregaría mi solución con escritura estática y administrador de contexto de closing .

 from contextlib import closing from typing import List import mysql.connector import logging logger = logging.getLogger(__name__) def execute(stmts: List[str]) -> None: logger.info("Starting daily execution") with closing(mysql.connector.connect()) as connection: try: with closing(connection.cursor()) as cursor: cursor.execute(' ; '.join(stmts), multi=True) except Exception: logger.exception("Rollbacking changes") connection.rollback() raise else: logger.info("Finished successfully")

Si no me equivoco, es posible que la conexión o el cursor no sean un administrador de contexto, según la versión del controlador mysql que tenga, por lo que es una solución segura para Python.

over 4 years ago · Santiago Trujillo Report

0

  1. executescript() Este es un método práctico para ejecutar varias sentencias SQL a la vez. Ejecuta el script SQL que obtiene como parámetro. Sintaxis:

    sqlite3.connect.executescript(script)

Código de ejemplo:

 import sqlite3 # Connection with the DataBase # 'library.db' connection = sqlite3.connect("library.db") cursor = connection.cursor() # SQL piece of code Executed # SQL piece of code Executed cursor.executescript(""" CREATE TABLE people( firstname, lastname, age ); CREATE TABLE book( title, author, published ); INSERT INTO book(title, author, published) VALUES ( 'Dan Clarke''s GFG Detective Agency', 'Sean Simpsons', 1987 ); """) sql = """ SELECT COUNT(*) FROM book;""" cursor.execute(sql) # The output in fetched and returned # as a List by fetchall() result = cursor.fetchall() print(result) sql = """ SELECT * FROM book;""" cursor.execute(sql) result = cursor.fetchall() print(result) # Changes saved into database connection.commit() # Connection closed(broken) # with DataBase connection.close()

Producción:

[(1,)] [("La agencia de detectives GFG de Dan Clarke", 'Sean Simpson', 1987)]

  1. ejecutar muchos () Suele ser el caso cuando se debe insertar una gran cantidad de datos en la base de datos desde archivos de datos (para un caso más simple, tome listas, matrices). Sería simple iterar el código muchas veces que escribir cada vez, cada línea en la base de datos. Pero el uso de bucle no sería adecuado en este caso, el siguiente ejemplo muestra por qué. La sintaxis y el uso de executemany() se explican a continuación y cómo se puede usar como un bucle:

Fuente: GeeksForGeeks: SQL usando Python Echa un vistazo a esta fuente... tiene muchas cosas geniales para ti.

over 4 years ago · Santiago Trujillo Report

0

La belleza está en el ojo del espectador, por lo que la mejor manera de hacer algo es subjetiva, a menos que nos digas explícitamente cómo medirla. Hay tres opciones hipotéticas que puedo ver:

  1. Use la opción multi de MySQLCursor (no ideal)
  2. Mantener la consulta en varias filas
  3. Mantener la consulta en una sola fila

Opcionalmente, también puede cambiar la consulta para evitar un trabajo innecesario.


Con respecto a la opción multi , la documentación de MySQL es bastante clara al respecto.

Si multi se establece en True, execute() puede ejecutar varias declaraciones especificadas en la cadena de operación. Devuelve un iterador que permite procesar el resultado de cada sentencia. Sin embargo, el uso de parámetros no funciona bien en este caso y, por lo general, es una buena idea ejecutar cada instrucción por separado .


Con respecto a la opción 2. y 3. es puramente una preferencia sobre cómo le gustaría ver su código. Recuerde que un objeto de conexión tiene autocommit=FALSE de forma predeterminada, por lo que el cursor en realidad procesa por lotes cursor.execute(...) en una sola transacción. En otras palabras, las dos versiones siguientes son equivalentes.

 self.cursor.execute('SET FOREIGN_KEY_CHECKS=0;') self.cursor.execute('DROP TABLE IF EXISTS %s;' % (table_name,)) self.cursor.execute('SET FOREIGN_KEY_CHECKS=1;') self.cursor.execute('CREATE TABLE %s select * from mytable;' % (table_name,))

contra

 self.cursor.execute( 'SET FOREIGN_KEY_CHECKS=0;' 'DROP TABLE IF EXISTS %s;' % (table_name,) 'SET FOREIGN_KEY_CHECKS=1;' 'CREATE TABLE %s select * from mytable;' % (table_name,) )

Python 3.6 introdujo cadenas f que son súper elegantes y deberías usarlas si puedes. :)

 self.cursor.execute( 'SET FOREIGN_KEY_CHECKS=0;' f'DROP TABLE IF EXISTS {table_name};' 'SET FOREIGN_KEY_CHECKS=1;' f'CREATE TABLE {table_name} select * from mytable;' )

Tenga en cuenta que esto ya no es válido cuando comienza a manipular filas; en este caso, se convierte en una consulta específica y debe generar un perfil si es relevante. Una pregunta SO relacionada es ¿Qué es más rápido, una consulta grande o muchas consultas pequeñas?


Finalmente, puede ser más elegante usar TRUNCATE en lugar de DROP TABLE a menos que tenga razones específicas para no hacerlo.

 self.cursor.execute( f'CREATE TABLE IF NOT EXISTS {table_name};' 'SET FOREIGN_KEY_CHECKS=0;' f'TRUNCATE TABLE {table_name};' 'SET FOREIGN_KEY_CHECKS=1;' f'INSERT INTO {table_name} SELECT * FROM mytable;' )
over 4 years ago · Santiago Trujillo Report

0

Yo crearía un procedimiento almacenado:

 DROP PROCEDURE IF EXISTS CopyTable; DELIMITER $$ CREATE PROCEDURE CopyTable(IN _mytable VARCHAR(64), _table_name VARCHAR(64)) BEGIN SET FOREIGN_KEY_CHECKS=0; SET @stmt = CONCAT('DROP TABLE IF EXISTS ',_table_name); PREPARE stmt1 FROM @stmt; EXECUTE stmt1; SET FOREIGN_KEY_CHECKS=1; SET @stmt = CONCAT('CREATE TABLE ',_table_name,' as select * from ', _mytable); PREPARE stmt1 FROM @stmt; EXECUTE stmt1; DEALLOCATE PREPARE stmt1; END$$ DELIMITER ;

y luego simplemente ejecuta:

 args = ['mytable', 'table_name'] cursor.callproc('CopyTable', args)

manteniéndolo simple y modular. Por supuesto, debe realizar algún tipo de comprobación de errores e incluso podría hacer que el procedimiento almacenado devuelva un código para indicar el éxito o el fracaso.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!