我有一个使用FTS4模块生成的SQLite表。每个条目至少列出两次使用不同的语言,但仍然共享一个唯一的ID(int列,未编入索引)。 这是我想要做的: 我想用首选语言查找术语。我想将结果与使用其他语言查找同一个术语结合起来。 但是对于第二次查找,我想忽略我在第一次查找期间找到的所有条目(由它们的ID标识)。所以基本上我想这样做:
WITH term_search1 AS (
SELECT *
FROM myFts
WHERE myFts MATCH 'term'
AND languageId = 1)
SELECT *
FROM term_search1
UNION
SELECT *
FROM myFts
WHERE myFts MATCH 'term'
AND languageId = 2
AND id NOT IN (SELECT id FROM term_search1)
这里的问题是,term_seach1查询将被执行两次。有没有办法实现我的结果呢?任何将其限制为2个查询(而不是3个)的解决方案都会很棒。
我也尝试过使用递归查询,例如:
WITH RECURSIVE term_search1 AS (
SELECT *
FROM myFts
WHERE myFts MATCH 'term'
AND languageId = 1
UNION ALL
SELECT m.*
FROM myFts m LEFT OUTER JOIN term_search1 t ON (m.id = t.id)
WHERE myFts MATCH 'term'
AND m.languageId = 2
AND t.id IS NULL
)
SELECT * FROM term_search1
这两项都不起作用。显然他刚刚为languageId = 2执行了两次查找(这可能是个错误吗?)。
提前致谢:)
答案 0 :(得分:4)
您可以使用TEMPORARY表将myFts的查询数量减少到2:
CREATE TEMP TABLE results (id INTEGER PRIMARY KEY);
INSERT INTO results
SELECT id FROM myFts
WHERE myFts MATCH 'term' AND languageId = 1;
INSERT INTO results
SELECT id FROM myFts
WHERE myFts MATCH 'term' AND languageId = 2
AND id NOT IN (SELECT id FROM results);
SELECT * FROM myFts
WHERE id IN (SELECT id FROM results);
DROP TABLE results;
如果可以更改架构,则只应将文本数据保留在FTS表中。这样,当您搜索数字时,您将避免不正确的结果,并且不希望匹配languageId
的行。创建另一个包含非文本数据的元表(如id
和languageId
),并通过加入rowid
的{{1}}来过滤行。 这样您只需要查询一次FTS表 - 使用临时表存储FTS表结果,然后使用元表对它们进行排序。
答案 1 :(得分:2)
这是我能想到的最好的:
SELECT *
FROM myFts t1
JOIN (SELECT COUNT(*) AS cnt, id
FROM myFts t2
WHERE t2.languageId in (1, 2)
AND t2.myFts MATCH 'term'
GROUP BY t2.id) t3
ON t1.id = t3.id
WHERE t1.myFts MATCH 'term'
AND t1.languageId in (1, 2)
AND (t1.languageId = 1 or t3.cnt = 1)
我不确定第二个MATCH
条款是否必要。
我们的想法是首先计算可接受的行数,然后选择最佳行。
修改:我不知道为什么它不适用于您的表格。这就是我测试它的方法(SQLite版本3.8.10.2):
CREATE VIRTUAL TABLE myFts USING fts4(
id integer,
languageId integer,
content TEXT
);
insert into myFts(id, languageId, content) values (10, 1, 'term 10 lang 1');
insert into myFts(id, languageId, content) values (10, 2, 'term 10 lang 2');
insert into myFts(id, languageId, content) values (11, 1, 'term 11 lang 1');
insert into myFts(id, languageId, content) values (12, 2, 'term 12 lang 2');
insert into myFts(id, languageId, content) values (13, 1, 'not_erm 13 lang 1');
insert into myFts(id, languageId, content) values (13, 2, 'term 13 lang 2');
执行查询给出:
sqlite> SELECT *
...> FROM myFts t1
...> JOIN (SELECT COUNT(*) AS cnt, id
...> FROM myFts t2
...> WHERE t2.languageId in (1, 2)
...> AND t2.myFts MATCH 'term'
...> GROUP BY t2.id) t3
...> ON t1.id = t3.id
...> WHERE t1.myFts MATCH 'term'
...> AND t1.languageId in (1, 2)
...> AND (t1.languageId = 1 or t3.cnt = 1);
10|1|term 10 lang 1|2|10
11|1|term 11 lang 1|1|11
12|2|term 12 lang 2|1|12
13|2|term 13 lang 2|1|13
sqlite>