Как искать строки с различными поисковыми данными (некоторые даны, некоторые нет) - PullRequest
1 голос
/ 31 марта 2019

Я использую операторы SQL для поиска строк в моей базе данных в зависимости от заданных данных. если столбцы (ID, Имя пользователя, Пароль, Распродажа, Class_Count), тогда моя программа будет иногда искать только имя пользователя или разрешение. Но иногда он будет искать как имя пользователя, так и количество классов. Мне неизвестны какие-либо способы, с помощью которых я могу легко реализовать это в своем коде, не создавая (я полагаю) около 7 различных операторов IF, чтобы проверить, какие данные используются для поиска (примеры будут приведены в следующем коде)

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

Из этой программы я в основном хочу более упорядоченный способ проверки того, какие данные предоставлены, и что мне нужно для запроса моей базы данных с помощью

Edit: Я сейчас попробовал метод при условии:

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

Однако теперь я получаю ошибку:

sqlite3.OperationalError: no such column: foo

где 'foo' - это имя пользователя, которое я ищу

Ответы [ 3 ]

1 голос
/ 31 марта 2019

Прямо сейчас ваши словарные ключи не соответствуют регистру столбцов вашей таблицы.Если бы вы могли это изменить, вы могли бы создать функцию, которая создает для вас условие WHERE:

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})  # -> ''

Преимущество этого подхода заключается в том, что он будет масштабироваться, если вы захотите включить больше строк в предложение WHEREбез необходимости добавления дополнительных if / elif операторов.

Если ваш details_dic также содержит другие ключи, которые не соответствуют столбцам в вашей таблице или которые вы не хотите включать в предложение WHERE,Вы можете добавить белый список в качестве второго параметра:

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
0 голосов
/ 31 марта 2019

Вы можете сделать что-то подобное с помощью f строк (https://www.python.org/dev/peps/pep-0498/) и троичных операторов:

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

Или, если имена столбцов вашей БД совпадают с именами ключей в details_dict, вы можетепопробуйте этот подход:

    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```
0 голосов
/ 31 марта 2019

Как насчет этого? Сделайте запрос строкой и списком параметров, которые построены с предложениями if, тогда вы можете написать один код execute / fetch. Мысль в псевдокоде выглядит примерно так:

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) 

Используется WHERE 1 = 1, поэтому исходный запрос будет выполнен и выберет все строки, если параметры не предоставлены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...