Nombre de la tabla variable en sqlite

Pregunta: ¿Es posible usar una variable como su nombre de tabla sin tener que usar constructores de cadenas para hacerlo?


Info:

Estoy trabajando en un proyecto ahora mismo que cataloga datos de una simulación de una estrella mía. Para ello estoy cargando todos los datos en una base de datos sqlite. Está funcionando bastante bien, pero he decidido agregar mucha más flexibilidad, eficiencia y facilidad de uso a mi db. Planeo agregar más adelante planetoides a la simulación, y quería tener una mesa para cada estrella. De esta manera no tendría que consultar una tabla de 20 m de algunos planetoides para el 1-4k en cada sistema solar.

Me han dicho que usar constructores de cadenas es malo porque me deja vulnerable a un ataque de inyección SQL. Si bien eso no es un gran problema ya que soy la única persona con acceso a estos dbs, me gustaría seguir las mejores prácticas. Y también de esta manera si hago un proyecto con una situación similar donde está abierto al público, sé qué hacer.

Actualmente estoy haciendo esto:

cursor.execute("CREATE TABLE StarFrame"+self.name+" (etc etc)") 

Esto funciona, pero me gustaría hacer algo más como:

 cursor.execute("CREATE TABLE StarFrame(?) (etc etc)",self.name) 

aunque entiendo que esto probablemente sería imposible. aunque me conformaría con algo como

 cursor.execute("CREATE TABLE (?) (etc etc)",self.name) 

Si esto no es posible, aceptaré esa respuesta, pero si alguien sabe cómo hacerlo, dígaselo. 🙂

Estoy codificando en python.

Desafortunadamente, las tablas no pueden ser el objective de la sustitución de parámetros (no encontré ninguna fuente definitiva, pero la he visto en algunos foros web).

Si está preocupado por la inyección (probablemente debería estarlo), puede escribir una función que limpie la cadena antes de pasarla. Dado que está buscando solo un nombre de tabla, debe estar seguro de que solo acepta caracteres alfanuméricos, eliminando toda puntuación, como por ejemplo )(][;, y espacios en blanco. Básicamente, mantenga AZ az 0-9 .

 def scrub(table_name): return ''.join( chr for chr in table_name if chr.isalnum() ) scrub('); drop tables --') # returns 'droptables' 

No separaría los datos en más de una tabla. Si crea un índice en la columna de la estrella, no tendrá ningún problema para acceder a los datos de manera eficiente.

Para las personas que buscan una forma de hacer la tabla como una variable, obtuve esto de otra respuesta a la misma pregunta aquí :

Dijo lo siguiente y funciona. Todo está citado de mhawke :

No puede utilizar la sustitución de parámetros para el nombre de la tabla. Debe agregar el nombre de la tabla a la cadena de consulta. Algo como esto:

 query = 'SELECT * FROM {}'.format(table) c.execute(query) 

Una cosa a tener en cuenta es la fuente del valor para el nombre de la tabla. Si eso proviene de una fuente no confiable, por ejemplo, un usuario, debe validar el nombre de la tabla para evitar posibles ataques de inyección de SQL. Una forma podría ser construir una consulta parametrizada que busque el nombre de la tabla en el catálogo de la base de datos:

 import sqlite3 def exists_table(db, name): query = "SELECT 1 FROM sqlite_master WHERE type='table' and name = ?" return db.execute(query, (name,)).fetchone() is not None 

Trate con el formato de cadena:

 sql_cmd = '''CREATE TABLE {}(id, column1, column2, column2)'''.format( 'table_name') db.execute(sql_cmd) 

Reemplace 'table_name' con su deseo.

puede usar algo como esto conn = sqlite3.connect() createTable = '''CREATE TABLE %s (# );''' %dateNow) conn.execute(createTable)

Como se ha dicho en las otras respuestas, “las tablas no pueden ser el objective de la sustitución de parámetros”, pero si se encuentra en un enlace en el que no tiene ninguna opción, aquí hay un método para probar si el nombre de la tabla proporcionado es válido.
Nota: he hecho que el nombre de la mesa sea un cerdo real en un bash de cubrir todas las bases.

 import sys import sqlite3 def delim(s): delims="\"'`" use_delim = [] for d in delims: if d not in s: use_delim.append(d) return use_delim db_name = "some.db" db = sqlite3.connect(db_name) mycursor = db.cursor() table = 'so""m ][ `etable' delimiters = delim(table) if len(delimiters) < 1: print "The name of the database will not allow this!" sys.exit() use_delimiter = delimiters[0] print "Using delimiter ", use_delimiter mycursor.execute('SELECT name FROM sqlite_master where (name = ?)', [table]) row = mycursor.fetchall() valid_table = False if row: print (table,"table name verified") valid_table = True else: print (table,"Table name not in database", db_name) if valid_table: try: mycursor.execute('insert into ' +use_delimiter+ table +use_delimiter+ ' (my_data,my_column_name) values (?,?) ',(1,"Name")); db.commit() except Exception as e: print "Error:", str(e) try: mycursor.execute('UPDATE ' +use_delimiter+ table +use_delimiter+ ' set my_column_name = ? where my_data = ?', ["ReNamed",1]) db.commit() except Exception as e: print "Error:", str(e) db.close() 

Puede pasar una cadena como el comando SQL:

 import sqlite3 conn = sqlite3.connect('db.db') c = conn.cursor() tablename, field_data = 'some_table','some_data' query = 'SELECT * FROM '+tablename+' WHERE column1=\"'+field_data+"\"" c.execute(query)