如何搜索具有不同搜索数据的行(有的给出,有的没有)

时间:2019-03-31 14:37:36

标签: python sqlite

我使用SQL语句根据给定的数据搜索数据库中的行。如果列是(ID,Username,Password,Clearance,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

从这个程序中,我基本上想要一种更简化的方式来检查给出了哪些数据以及我需要使用什么来查询数据库

编辑: 我现在尝试了提供的方法:

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 个答案:

答案 0 :(得分:1)

现在,您的字典键与表列的大小写不匹配。 如果可以更改它,则可以创建一个为您创建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

答案 1 :(得分:0)

这样的事情怎么样?使查询成为使用if子句构建的字符串和参数列表,然后可以编写一个执行/提取代码。这个想法是用伪代码这样的:

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,以便在不提供参数的情况下运行原始查询并选择所有行。

答案 2 :(得分:0)

您可以借助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```