SQLite3如何将IN运算符与LIKE运算符结合在一起以获取与子查询匹配的部分文本?

时间:2018-10-11 07:10:56

标签: sqlite

我正在尝试检测数据库中的重复项。我想出一个我想做的MWE。并非每个id列都有一个值,但是id可能仍在文件名中。我正在尝试查找具有ID的所有行,该ID出现在不同行的文件名中。

enter image description here

这个查询是我要寻找的一种,但是问题是进行精确匹配

SELECT * FROM items WHERE id IN (
    SELECT filename FROM items
);

IN运算符的缩写为:

name IN ("Bob Walters", "Alice Reed") ==> name == "Bob Walters" OR name = "Alice Reed"

但是我希望操作员执行此操作:

_________ ==> "%" || name || "%" LIKE "Bob Walters" OR "%" || name || "%" LIKE "Alice Reed"

我正在寻找可以在空白处放入的内容以实现此操作。我的表只有10,000多行(因此,该解决方案不一定必须针对数百万行进行优化)。

3 个答案:

答案 0 :(得分:2)

您想要的是EXISTS,而不是IN。试试:

SELECT *
FROM items AS i
WHERE EXISTS (SELECT *
              FROM items AS i2
              WHERE i.filename LIKE '%' || i2.id || '%' AND i.filename <> i2.filename)

答案 1 :(得分:1)

如果您使用的是SQLite 3+,则可以尝试使用REGEXP运算符:

SELECT *
FROM items i1
WHERE EXISTS (SELECT 1 FROM items i2
              WHERE i2.filename REGEXP '\b' || i1.id || '\b' AND
              i1.id <> i2.id);

如果您的SQLite版本不支持REGEXP,那么您可以 在其位置使用LIKE

SELECT *
FROM items i1
WHERE EXISTS (SELECT 1 FROM items i2
              WHERE i2.filename LIKE '%' || i1.id || '%' AND
              i1.id <> i2.id);

我在上面强调了 can ,因为LIKE和通配符的问题在于它不仅会匹配完全匹配的内容,而且还会匹配子字符串,例如如果id=34983在另一个记录中作为文件名中另一个ID的子字符串出现,则将出现误报。

答案 2 :(得分:0)

我尝试过的事情

  1. 结合使用WHERE EXISTS运算符和LIKE运算符(在10,000个项目的数据库上大约50秒)

    SELECT * FROM items AS i1 WHERE EXISTS (
        SELECT * FROM items AS i2 WHERE i1.id != i2.id AND i2.filename LIKE '%' || i1.id || '%'
    );
    
  2. 结合使用WHERE EXISTS运算符和instr函数(在10,000个项目的数据库上大约50秒)

    SELECT * FROM items AS i1 WHERE EXISTS (
        SELECT * FROM items AS i2 WHERE i1.id != i2.id AND instr(i2.filename, i1.id) != 0
    );
    
  3. 结合使用WHERE EXISTS运算符和LIKE运算符,并仅查看具有空id的行(在10,000个项目的数据库中为30秒)

  4. 结合使用WHERE EXISTS运算符和instr函数,并仅查看具有空id的行(在10,000个项目的数据库中为30秒)
  5. 在Python中,获取ID列表,然后为每个ID调用数据库以查找匹配项(在10,000个项目的数据库中约17秒)
  6. 在Python中,从数据库中获取ID和文件名的列表,然后在Python中进行搜索(在10,000个项目的数据库中约10秒)<--我使用的解决方案

其他可能的解决方案

  1. WHERE EXISTS运算符与REGEXP运算符结合使用
  2. 启用FTS4全文搜索扩展并创建虚拟表,因此将WHERE EXISTS运算符与MATCH运算符(或另一个FTS4运算符)结合使用
  3. 在Python中使用SQLAlchemy
  4. 重组数据库(例如,将文件名中的ID相似项从文件名中拉出到单独的ID列中,因此我们可以进行精确的列匹配而不是通配符搜索)

我的解决方案的代码

statement_id = 'SELECT * FROM items WHERE id IS NOT NULL and id != ""'
cursor.execute(statement_id)
ids = cursor.fetchall()

statement_title = 'SELECT * FROM items WHERE title IS NOT NULL AND title != ""'
cursor.execute(statement_title)
titles = cursor.fetchall()

matches = []
for id in ids:
    for title in titles:
        if id['id'] in title['title']:
            matches.append([id, title])

结论

总而言之,解决方案很丑陋,但我认为在这种情况下(这是一个个人项目,我不会经常进行这种重复数据删除操作,等等)。我认为全文扩展或重组数据库可能是更好的解决方案。