2008-10-23 20 views
49

Al usar SQLite3 con Python 2.5, estoy tratando de recorrer una lista y obtener el peso de un elemento de la base de datos basado en el nombre del elemento.Problema de sustitución de parámetros SQLite

He intentado utilizar el "?" sustitución de parámetros sugerida para evitar inyecciones de SQL, pero no funciona. Por ejemplo, cuando uso:

for item in self.inventory_names: 
    self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", item) 
    self.cursor.close() 

me sale el error:

sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 1, and there are 8 supplied.

Creo que esto es de alguna manera causada por la creación inicial de la base de datos; el módulo que hice que realmente crea el DB tiene 8 enlaces.

cursor.execute("""CREATE TABLE Equipment 
    (id INTEGER PRIMARY KEY, 
    name TEXT, 
    price INTEGER, 
    weight REAL, 
    info TEXT, 
    ammo_cap INTEGER, 
    availability_west TEXT, 
    availability_east TEXT)""") 

Sin embargo, cuando se utiliza la sustitución del "% s" menos seguro para cada nombre del elemento, funciona muy bien. De esta manera:

for item in self.inventory_names: 
    self.cursor.execute("SELECT weight FROM Equipment WHERE name = '%s'" % item) 
    self.cursor.close() 

No puedo entender por qué cree que tengo 8 enlaces cuando solo estoy llamando a uno. ¿Cómo puedo arreglarlo?

+0

El número de columnas no es el número de enlaces. El número de "?" En la consulta es el número de enlaces. –

+0

Sí, lo sé. Me imaginé que el código de alguna manera estaba tratando de usar los enlaces a los que hace referencia la sentencia "create table". No me di cuenta de que se refería a la cantidad de letras en el artículo en sí. – crystalattice

Respuesta

118

El método Cursor.execute() espera una secuencia como segundo parámetro. Está suministrando una cadena que tiene 8 caracteres de largo.

Utilice el siguiente formulario en su lugar:

self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", [item]) 

Python 13.13.3 referencia de la biblioteca: sqlite3 Cursor Objects.

2

intenté? :

for item in self.inventory_names: 
    t = (item,) 
    self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", t) 
    self.cursor.close() 

cursor.execute() espera una secuencia (lista, tupla) como segundo parámetro. (-> ddaa)

35

he pasado medio día tratando de averiguar por qué algo como esto me daría un error:

cursor.execute("SELECT * from ? WHERE name = ?", (table_name, name)) 

sólo para descubrir que los nombres de las tablas no se puede parametrizar. Espero que esto ayude a otras personas a ahorrar algo de tiempo.

+1

Puede hacer algo como: 'cursor.execute (" SELECT * from% s WHERE name =? "% Table_name, (name,))', aunque eso puede hacer que su programa sea vulnerable a ataques de inyección SQL. – plok

+6

Para las situaciones donde la entrada del usuario determina la tabla, saco el nombre de la tabla de un dict y hago una excepción si el contenido de la entrada es inesperado. Probablemente no sea la mejor manera de hacerlo, pero parece menos probable que resulte en una inyección SQL. – James

+0

@James Tengo curiosidad, ¿en qué situaciones ha tenido que cambiar qué tabla está insertando en función de la entrada del usuario? Usar un dict suena como una muy buena idea para esa situación, los uso cada vez que hubiera usado una declaración de cambio. – num1

1

Citando (¿eso es lo que significan los parens?) El? con parens parece funcionar para mí. Seguí intentando con (literalmente) '?' pero seguí recibiendo

ProgrammingError: Incorrect number of bindings supplied. The current statement uses 0, and there are 1 supplied.

Cuando lo hice:

SELECT fact FROM factoids WHERE key LIKE (?)

en lugar de:

SELECT fact FROM factoids WHERE key LIKE '?'

Funcionó.

¿Es esto algo de Python 2.6?

+1

Si usa la sustitución de parámetros de sqlite3 (en lugar de la interpolación de cadenas de% s de Python), ¿entonces? ¿no debería citarse en absoluto, es decir, 'SELECCIONAR hecho FROM factoids WHERE clave LIKE?'. Simplemente sucede que la adición de corchetes en el SQL no cambia el significado, por lo que 'SELECCIONAR hecho FROM fácticos DONDE la clave LIKE (?)' Es equivalente a sin(). –

+0

Si está utilizando Django y su consulta es 'SELECCIONAR hecho DESDE fácticos DONDE la clave TIENE GUSTO"% s "', entonces también querrá evitar las comillas. 'cursor.execute()' no reconocerá% s como un enlace en esa consulta. Así que use 'cursor.execute (" Seleccionar hecho FROM factoids WHERE clave LIKE% s ", (key_name,))' – MrOodles

-5

Trate

execute("select fact from factoids where key like ?", "%%s%" % val) 

no envuelve ningún objeto alrededor del ? en absoluto, Python sqlite convertirá correctamente en una entidad citada.

21

El argumento de cursor.execute que representa los valores que necesita insertar en la base de datos debe ser una tupla (secuencia). Sin embargo, considere este ejemplo y vea lo que está sucediendo:

>>> ('jason') 
'jason' 

>>> ('jason',) 
('jason',) 

El primer ejemplo se evalúa como una cadena; por lo que la forma correcta de representar la tupla de un solo valor es como en la segunda evaluación. De todos modos, el código a continuación para corregir su error.

self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", (item,)) 

también dando los argumentos cursor.execute de valor como cadenas, (que es lo que está haciendo) los resultados de la primera evaluación en el ejemplo y los resultados en el error que está recibiendo.

+2

Creo que esta debería ser la respuesta aceptada – Kirk

0

cada elemento de los elementos tiene que ser una tupla. nombres asumiendo ve algo como esto:

names = ['Joe', 'Bob', 'Mary'] 

usted debe hacer lo siguiente:

for item in self.inventory_names: 
self.cursor.execute("SELECT weight FROM Equipment WHERE name = ?", (item,)) 

utilizando (punto), que está haciendo que sea una tupla en lugar de una cadena.

Cuestiones relacionadas