J'utilise des instructions SQL pour rechercher des lignes dans ma base de données en fonction des données données. si les colonnes sont (ID, Username, Password, Clearance, Class_Count), mon programme ne recherchera parfois que le nom d'utilisateur ou l'autorisation. Mais parfois, il recherchera à la fois le nom d'utilisateur et le nombre de classes. Je ne connais aucun moyen de l'implémenter facilement dans mon code sans créer (je crois) environ 7 instructions IF différentes pour vérifier quelles données sont utilisées pour la recherche (des exemples seront donnés dans le code ci-dessous)
sqlite3.OperationalError: no such column: foo
À partir de ce programme, je souhaite essentiellement un moyen plus simple de vérifier quelles données sont fournies et ce dont j'ai besoin pour interroger ma base de données avec
Modifier: J'ai maintenant essayé une méthode fournie:
def Create_Where_Condition(self, Details_Dic): print("In Where Condition") Where_Condition = "" for Key, Value in Details_Dic.items(): print("Key:",Key) print("Value:", Value) if Value is not None: Prefix = " AND " if Where_Condition else " WHERE " Where_Condition += Prefix + "{}={}".format(Key, Value) return Where_Condition def Get_Users_DB(self,Search_Data): print("In get_user_db") Details_Dic = Create_User_Dict((None, Search_Data[0], None, Search_Data[1], Search_Data[2])) print("after details_dic") SQL_Statement = "SELECT * FROM USERS" + self.Create_Where_Condition(Details_Dic) print("SQL STATEMENT:\n{}".format(SQL_Statement)) try: # Defensive programming to prevent database errors from stopping the program from running with global_lock: self.DB_Cursor.execute(SQL_Statement) User_Data = self.DB_Cursor.fetchall() print(User_Data) if User_Data: # If any value was returned from the database User_Dict_List = [] for User_Details in User_Data: # For every user in the list convert them to a dictionary User_Dict = Create_User_Dict(User_Details) User_Dict_List.append(User_Dict) return User_Dict_List else: return False # Tell called from function that the user does not exist except sqlite3.Error as Err: # If an error occurs display a message in the console Error_Report(Err, "Get_User_DB") return False # Tell called from function that the function was unsuccessful
Cependant maintenant j'obtiens l'erreur:
def Get_Users_DB(self, Search_Data): Details_Dic = Create_User_Dict((None,Search_Data[0],None,Search_Data[1],Search_Data[2])) try: # Defensive programming to prevent database errors from stopping the program from running with global_lock: if Details_Dic["Username"]: # If a username is given, no other values need to be checked as username are unique self.DB_Cursor.execute("SELECT * FROM USERS WHERE username = ?", (Details_Dic["Username"],)) # Selects user from USERS table based on the username provided User_Data = self.DB_Cursor.fetchall() # Fetches the user if applicable, returns as a list for processing purposes elif Details_Dic["Clearance"] and Details_Dic["Class_Count"] is not None: print("Here b0ss") # If there is a value for clearance and Class_Count is not a none type self.DB_Cursor.execute("SELECT * FROM USERS WHERE\ clearance = ? AND Class_Count = ?", (Details_Dic["Clearance"], Details_Dic["Class_Count"])) # Select all users based on these restrictions User_Data = self.DB_Cursor.fetchall() elif Details_Dic["Clearance"]: # If only a clearance level is given self.DB_Cursor.execute("SELECT * FROM USERS WHERE\ clearance = ?", (Details_Dic["Clearance"],)) User_Data = self.DB_Cursor.fetchall() elif Details_Dic["Class_Count"] is not None: # If only a class value is given self.DB_Cursor.execute("SELECT * FROM USERS WHERE\ Class_Count = ?", (Details_Dic["Class_Count"],)) User_Data = self.DB_Cursor.fetchall() else: # If no values are given, get all users self.DB_Cursor.execute("SELECT * FROM USERS") User_Data = self.DB_Cursor.fetchall() if User_Data: # If any value was returned from the database User_Dict_List = [] for User_Details in User_Data: # For every user in the list convert them to a dictionary User_Dict = Create_User_Dict(User_Details) User_Dict_List.append(User_Dict) return User_Dict_List else: return False # Tell called from function that the user does not exist except sqlite3.Error as Err: # If an error occurs display a message in the console Error_Report(Err, "Get_User_DB") return False # Tell called from function that the function was unsuccessful
où 'foo' est le nom d'utilisateur que je recherche
3 Réponses :
Et quelque chose comme ça? Faites de la requête une chaîne et une liste de paramètres construits avec les clauses if
, vous pouvez alors coder une exécution / extraction. La pensée est quelque chose comme ceci dans le pseudo code:
query = "SELECT * from users WHERE 1 = 1" if username then query += "AND username = ?", params.push[username] else if clearance then query += "AND clearance = ?", params.push[clearance] if class_count then query += "AND class_count =?",params.push[class_count] execute(query,params)
Le WHERE 1 = 1
est utilisé pour que la requête originale s'exécute et sélectionne toutes les lignes lorsqu'aucun paramètre n'est fourni .
Pour le moment, vos clés de dictionnaire ne correspondent pas à la casse des colonnes de votre table.
Si vous pouviez changer cela, vous pourriez créer une fonction qui crée la condition WHERE
pour vous:
def create_where_condition(details_dic, rows_to_include): where_condition = "" for key, value in details_dic.items(): if key in rows_to_include and value is not None: if isinstance(value, str): value = '"' + value + '"' prefix = " AND " if where_condition else " WHERE " where_condition += prefix + '{}={}'.format(key, value) return where_condition
Cette approche a l'avantage qu'elle sera mise à l'échelle si vous le souhaitez inclure plus de lignes dans la clause WHERE sans avoir à ajouter des instructions supplémentaires if
/ elif
.
Si votre details_dic contient également d'autres clés qui ne correspondent pas à colonnes de votre tableau ou que vous n'aimez pas inclure dans la clause WHERE, vous pouvez ajouter une liste blanche comme deuxième paramètre:
def create_where_condition(details_dic): where_condition = "" for key, value in details_dic.items(): if value is not None: prefix = " AND " if where_condition else " WHERE " where_condition += prefix + '{}="{}"'.format(key, value) return where_condition create_where_condition({"username": "Tom", "clearance": None, "Class_Count": 10}) # -> ' WHERE username=Tom AND Class_Count=10' create_where_condition({"username": "Tom", "clearance": 100, "Class_Count": 10}) # -> ' WHERE username=Tom AND clearance=100 AND Class_Count=10' create_where_condition({"username": None, "clearance": None, "Class_Count": None}) # -> ''
J'ai essayé votre méthode, cependant chaque fois que j'exécute l'instruction (j'ajoute «SELECT * FROM TABLE»), cela me dit que «input_username» n'est pas une colonne.
C'est ce que je voulais dire avec le premier paragraphe. Si vous souhaitez utiliser cette fonction, vous devrez modifier vos clés de dictionnaire pour qu'elles correspondent au nom de vos colonnes. Je vois que vous avez ajouté ma fonction à votre message de démarrage et que vous obtenez une erreur pour une clé "foo", ce qui signifie que vous devez également inclure une liste blanche comme dans ma deuxième implémentation.
Je l'ai fait cependant. Pourquoi prend-il la partie 'foo' comme colonne de toute façon, si username est le nom de la colonne, pourquoi 'foo' serait-il utilisé?
Aka mon dictionnaire est {"Username": "Foo"}
J'ai découvert quelle est l'erreur. Dans le code que vous m'avez donné, si la valeur est une chaîne, elle n'est pas entourée de guillemets, ce qui signifie qu'une valeur de chaîne sera considérée comme une colonne
J'ai donc besoin de trouver un moyen pour que toutes les valeurs de chaîne soient entourées de guillemets supplémentaires
Vous m'avez battu d'une minute. J'ai mis à jour la réponse maintenant. Ma faute.
Cela ne fonctionne pas non plus, car les valeurs entières seraient alors comptées comme des chaînes. J'ai donc ajouté une autre instruction if 'If isinstance (Value, str): Value = "'" + Value + "'"
Vous avez raison, malheureusement j'ai rejeté votre proposition d'édition avant de lire votre commentaire. J'ai mis à jour la réponse.
Bon truc, je peux le sélectionner comme réponse maintenant. Aucune des autres solutions n'est mauvaise, mais c'est celle que j'ai utilisée
Vous pouvez faire quelque chose comme ça à l'aide de chaînes f ( https: / /www.python.org/dev/peps/pep-0498/ ) et opérateurs ternaires:
details_dict = create_user_dict((None, search_data[0], None, search_data[1], search_data[2])) with global_lock: sql_query = f""" SELECT * from USERS WHERE 1=1 """ # We can interpolate strings using dictionary keys for field_name in details_dict.keys(): sql_query += f" AND {field_name}=%({field_name})s " self.db_cursor.execute(sql_query, details_dict) except sqlite3.Error as Err: Error_Report(Err, "Get_User_DB") return False```
Ou si les noms de vos colonnes DB correspondent aux noms de clés dans le details_dict, vous pouvez essayez cette approche:
def query_users(self, search_data): details_dict = create_user_dict((None, search_data[0], None, search_data[1], search_data[2])) with global_lock: # Named parameters in query looks like this %(<named_param>)s sql_query = f""" SELECT * from USERS WHERE 1=1 {"AND username=%(username)s" if details_dict.get("username") else ""} {"AND clearance=%(clearance)s" if details_dict.get("clearance") else ""} {"AND Class_Count=%(class_count)s" if details_dict.get("class_count") else ""}; """ # Execute methods provides possibility of using named parameters which are already in the details_dict self.db_cursor.execute(sql_query, details_dict) except sqlite3.Error as Err: Error_Report(Err, "Get_User_DB") return False