【问题标题】:Search (SQLite3) database using multiple words使用多个词搜索(SQLite3)数据库
【发布时间】:2017-05-12 18:49:10
【问题描述】:

(如果你能想到更好的标题请说)

所以我有一个数据库,其中包含我希望能够搜索的表。搜索,如我有输入 intel core i5 并且我想获取列 Name 中包含 intelcorei5 的任何行,以任何排列方式、围绕这些单词或任何其他单词的字符。

到目前为止,我正在做:

search = "intel core i5" # This is taken from an entry field.
words = []
for word in search.split()
    words.append("%" + word.strip() + "%")
results = db_handler.query("""SELECT Table1.ID 
                              FROM Table1 
                                  JOIN Table2 
                                  ON Table1.ID2 = Table2.ID 
                              WHERE Table2.Name LIKE({0}) AND 
                                  Active=1""".format(", ".join("?" for _ in self.words)), self.words)
# db_handler.query is a method which queries and returns results. Plus some other stuff.
# In Table1 there is some columns like ID, ID2, Active, eta
# ID2 matches ID in Table2 which also contains Name
# So I want ID from Table1 searched by Name from Table2  

但这不起作用,因为 LIKE 不需要多个参数。 (可能有比拆分输入更好的方法,但我这样做是因为这是有道理的,是吗?)我看到一些人提出了一些不同的问题,建议使用 REGEXP,但我已经看过了,但是并没有真正得到它供我使用。如果这是最好的,你能解释一下如何谢谢。我该怎么做?

谢谢

【问题讨论】:

    标签: python sql python-3.x sqlite


    【解决方案1】:

    LIKE 采用一种模式,但您可以在其中包含多个关键字,例如:

    ... LIKE '%intel%core%i5%' ...
    

    这将匹配包含 intel 后跟 core 后跟 i5 的值,以及之前、之后和中间的任意字符串。

    要查找包含任何安排的记录, 您需要使用所有排列的多个LIKE子句(本例中有6个),并将它们一起使用OR,例如:

    ... (Table2.Name LIKE '%intel%core%i5%' OR Table2.Name LIKE '%intel%i5%core%' OR ...) ...
    

    在上下文中:

    from itertools import permutations
    
    search = "intel core i5"
    words = [word.strip() for word in search.split()]
    combinations = ["%" + "%".join(order) + "%" for order in list(permutations(words)]
    sql = """SELECT <Columns> FROM <Table> 
             WHERE [Other ...] 
                 (<Col> LIKE {0})""".format(" OR <Col> LIKE ".join("?" for _ in combinations))
    values = combinations # sql and values/combinations to be sent to a query function.
    

    【讨论】:

    • 谢谢。由于输入不受限制,我必须动态创建查询长度,我现在就是这样,但我还必须生成所有组合。这可以做到,但有没有更优雅/简单的解决方案?
    • 不,SQL 没有这样的运算符来帮助您匹配多个关键字的任何排列。按照我的建议,暴力破解所有排列是唯一的方法。
    • 但是,您可以使用itertools.permutations在 Python 中轻松生成排列
    • 我知道一点关于 itertools 但不知道 permtations。我会看一下文档,但它需要 args 并返回所有可能的组合吗?
    • 例如list(itertools.permutations(('intel', 'i5', 'core'), 3)) 将给出长度为 3 的所有 6 个组合。
    【解决方案2】:

    让我们假设(考虑一般问题)您希望能够在列表中找到包含任何或所有单词的行,或者在列col 中设置words。让我们进一步假设您完全了解 SQL 注入攻击的风险,因此您在将任何用户输入包含在 words 之前对其进行了全面清理。

    单个词w你想要的查询条件在Python中可以表示为

    "{0} LIKE '%{}%'".format(col, w)
    

    单个字段查询需要与“OR”连接以查找任何术语或“AND”以查找所有术语。所以你可以将joiner设置为' AND '' OR ',然后整个查询搜索条件将是

    joiner.join(["{0} LIKE '%{1}%'".format(col, w) for w in words])
    

    如果你设置了

    words = "intel core i5".split()
    joiner = " AND "
    col = "Table2.name"
    

    计算结果为

    Table2.name LIKE '%intel%' AND Table2.name LIKE '%core%' AND Table2.name LIKE '%i5%'
    

    你显然已经知道足够多的 Python 来做你想做的事了。

    【讨论】:

    • 不错的概述。 python的sqlite3模块查询提供了多少保护(“?”(值,))对sql注入,就像我读过的那样?对于我的产品来说,数据库是用户存储的,桌面只能由用户访问,这并不重要。唯一的方法可能是通过仅从 pcpp 网站获取数据的 web-scraper,如果这有任何改变,它也会通过 beautifulsoup4 进行过滤。另一个问题:如果您要包含的结果少于所有结果,您会希望按相关性列出它们,因此结果也需要相关性值。
    • 如果您在驱动程序中使用参数替换,您应该免受 SQL 注入的影响。不幸的是,不能对表名和列名进行参数化,只能对值进行参数化。我什至没有考虑相关性分数——这需要一种更有条理的存储和搜索方法。
    猜你喜欢
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 2021-05-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-30
    • 1970-01-01
    • 2012-12-16
    相关资源
    最近更新 更多