web-dev-qa-db-fra.com

Problème de substitution de paramètre SQLite

À l'aide de SQLite3 avec Python 2.5, j'essaie de parcourir une liste et d'extraire le poids d'un élément de la base de données en fonction de son nom.

J'ai essayé d'utiliser le "?" substitution de paramètres suggérée pour empêcher les injections SQL mais cela ne fonctionne pas. Par exemple, quand j'utilise:

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

Je reçois l'erreur:

sqlite3.ProgrammingError: Nombre incorrect de liaisons fournies. La déclaration en cours utilise 1, et il y en a 8 fournis.

Je crois que cela est en quelque sorte causé par la création initiale de la base de données; le module que j'ai créé et qui crée effectivement la base de données possède 8 liaisons.

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)""")

Cependant, lorsque j'utilise la substitution moins sécurisée "% s" pour chaque nom d'élément, cela fonctionne parfaitement. Ainsi:

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

Je n'arrive pas à comprendre pourquoi je pense avoir 8 bindins alors que je n'en appelle qu'un. Comment puis-je le réparer?

55
crystalattice

La méthode Cursor.execute() attend une séquence en tant que second paramètre. Vous fournissez une chaîne de 8 caractères.

Utilisez plutôt le formulaire suivant:

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

Référence de la bibliothèque Python: sqlite3 Cursor Objects .

126
ddaa

J'ai passé une demi-journée à essayer de comprendre pourquoi quelque chose comme ça me donnerait une erreur:

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

seulement pour savoir que les noms de table ne peuvent pas être paramétrés . J'espère que cela aidera d'autres personnes à gagner du temps.

49
ccpizz

L'argument de cursor.execute qui représente les valeurs à insérer dans la base de données doit être un Tuple (séquence). Cependant, considérons cet exemple et voyons ce qui se passe:

>>> ('jason')
'jason'

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

Le premier exemple correspond à une chaîne. la manière correcte de représenter un tuple à valeur unique est donc identique à celle de la deuxième évaluation. Quoi qu'il en soit, le code ci-dessous pour corriger votre erreur.

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

Donner également les arguments de valeur cursor.execute sous forme de chaînes (ce que vous êtes en train de faire) entraîne la première évaluation de l'exemple et aboutit à l'erreur que vous obtenez.

22
jgtumusiime

avez-vous essayé cela? :

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

cursor.execute () attend une séquence (list, Tuple) comme second paramètre. (-> ddaa)

2
Blauohr

Citer (est-ce ce que les parens veulent dire?) Le? avec parens semble fonctionner pour moi. J'ai continué d'essayer avec (littéralement) '?' mais je continuais à obtenir

ProgrammingError: Nombre incorrect de liaisons fournies. L'instruction en cours utilise 0, et il y en a 1 fourni.

Quand j'ai fait:

SÉLECTIONNER LE FAIT DES FAITS OU LA touche LIKE (?)

au lieu de:

SÉLECTIONNER LE FAIT DES FAITS OU O WH LA CLÉ AIME '?

Ça a marché.

Est-ce quelque chose de python 2.6?

1
kjikaqawej

Le module sqlite3 prend en charge deux types d'espaces réservés pour les paramètres:

style qmark

Utilisez un ou plusieurs ? pour marquer la position de chaque paramètre et fournissez une liste ou un tuple de paramètres. Par exemple.:

curs.execute("SELECT weight FROM Equipment WHERE name = ? AND price = ?",
             ['lead', 24])

style nommé

Utilisez les espaces réservés :par pour chaque paramètre nommé et fournissez un dict. Par exemple.:

curs.execute("SELECT weight FROM Equipment WHERE name = :name AND price = :price",
             {name: 'lead', price: 24})

L'avantage des paramètres de style nommés est que vous n'avez pas à vous soucier de l'ordre des paramètres et chaque :par peut être utilisé plusieurs fois dans des requêtes SQL volumineuses/complexes.

0
Mike T

chaque élément d'éléments doit être un tuple . en supposant que les noms ressemblent à ceci

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

vous devriez faire ce qui suit:

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

en utilisant (item), vous en faites un tuple au lieu d’une chaîne.

0
Joey Nelson