6

我有一个使用 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 执行了两次查找(这可能是一个错误吗?)。

提前致谢 :)

4

2 回答 2

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过滤行。这样,您只需查询 FTS 表一次- 使用临时表存储 FTS 表结果,然后使用元表对它们进行排序。rowidmyFts

于 2015-07-24T11:45:59.343 回答
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> 
于 2015-07-27T17:16:39.460 回答