在没有部分索引的 SQLite table 中查找 "best partial match"
Finding a "best partial match" in a SQLite table without a partial index
在我使用 SQLite 存储用户数据的 Android 应用程序中,我有一个名为 valency
的 table,如下所示。
CREATE TABLE IF NOT EXISTS valency(urid INTEGER PRIMARY KEY AUTOINCREMENT,typ INTEGER,entity INTEGER,v0 INTEGER,v1 INTEGER,v2 INTEGER,v3 INTEGER,v4 INTEGER,v5 INTEGER,lato INTEGER,data INTEGER DEFAULT 0);
CREATE INDEX IF NOT EXISTS vTypEnt ON valency(typ,entity);
我需要为 typ
和 entity
中的 table 列 v0.. v5
中的行找到 "best" 匹配项列。匹配的列数越多,我想附加到匹配的data
列的权重就越大。
这就是我的流程
第 1 步 - 将相关行读入 TEMP table
CREATE TEMP TABLE H1 AS SELECT * FROM valency WHERE (typ = T) AND (entity = E);
将 v0..v5
值设置为 1 或 0,具体取决于它们是否匹配
UPDATE H1 SET
v0 = CASE WHEN (v0 = V0) THEN 1 ELSE 0 END,
v1 = CASE WHEN (v1 = V1) THEN 1 ELSE 0 END,
v2 = CASE WHEN (v2 = V2) THEN 1 ELSE 0 END,
v3 = CASE WHEN (v3 = V3) THEN 1 ELSE 0 END,
v4 = CASE WHEN (v4 = V4) THEN 1 ELSE 0 END,
v5 = CASE WHEN (v5 = V5) THEN 1 ELSE 0 END;
这通常会导致 H1
中的一行或多行,其中零个或多个 v*
值设置为 0,而其他值设置为 1。我真正关心的是 "best" 匹配 - 即识别具有最多非零 v*
值的行。
步骤 3
SELECT urid,lato,data,v0 + v1 + v2 + v3 + v4 + v5 as 'vSum' FROM H1 ORDER BY vSum DESC LIMIT 1;
隔离具有 "best" 匹配项的行。在使用和操作此结果行中最匹配的 data
之前,我使用 vSum
的大小为数据分配权重。
这非常有效。但是,我不是 SQL 专家,所以我不禁想知道是否可能没有 better/simpler/faster 方法来完成同样的事情。必须使用它的上下文不需要速度,所以我不热衷于使用更多存储和更多索引的权衡。如果有人能对我的方法发表评论并提出改进建议,我将不胜感激。
您可以通过一次计算分数将select转换为一个SELECT
语句。这消除了临时 table 和代码与数据库引擎之间的一些往返的需要:
select
*
, CASE WHEN (v0 = V0) THEN 1 ELSE 0 END
+CASE WHEN (v1 = V1) THEN 1 ELSE 0 END
+CASE WHEN (v2 = V1) THEN 1 ELSE 0 END
+CASE WHEN (v3 = V3) THEN 1 ELSE 0 END
+CASE WHEN (v4 = V4) THEN 1 ELSE 0 END
+CASE WHEN (v5 = V5) THEN 1 ELSE 0 END
+ ... as vSum
FROM valency
WHERE (typ = T)
AND (entity = E)
order by vSum desc
limit 1
您可能希望向 order by
子句添加更多条件,以确保您的顺序在运行之间保持一致。
在我使用 SQLite 存储用户数据的 Android 应用程序中,我有一个名为 valency
的 table,如下所示。
CREATE TABLE IF NOT EXISTS valency(urid INTEGER PRIMARY KEY AUTOINCREMENT,typ INTEGER,entity INTEGER,v0 INTEGER,v1 INTEGER,v2 INTEGER,v3 INTEGER,v4 INTEGER,v5 INTEGER,lato INTEGER,data INTEGER DEFAULT 0);
CREATE INDEX IF NOT EXISTS vTypEnt ON valency(typ,entity);
我需要为 typ
和 entity
中的 table 列 v0.. v5
中的行找到 "best" 匹配项列。匹配的列数越多,我想附加到匹配的data
列的权重就越大。
这就是我的流程
第 1 步 - 将相关行读入 TEMP table
CREATE TEMP TABLE H1 AS SELECT * FROM valency WHERE (typ = T) AND (entity = E);
将 v0..v5
值设置为 1 或 0,具体取决于它们是否匹配
UPDATE H1 SET
v0 = CASE WHEN (v0 = V0) THEN 1 ELSE 0 END,
v1 = CASE WHEN (v1 = V1) THEN 1 ELSE 0 END,
v2 = CASE WHEN (v2 = V2) THEN 1 ELSE 0 END,
v3 = CASE WHEN (v3 = V3) THEN 1 ELSE 0 END,
v4 = CASE WHEN (v4 = V4) THEN 1 ELSE 0 END,
v5 = CASE WHEN (v5 = V5) THEN 1 ELSE 0 END;
这通常会导致 H1
中的一行或多行,其中零个或多个 v*
值设置为 0,而其他值设置为 1。我真正关心的是 "best" 匹配 - 即识别具有最多非零 v*
值的行。
步骤 3
SELECT urid,lato,data,v0 + v1 + v2 + v3 + v4 + v5 as 'vSum' FROM H1 ORDER BY vSum DESC LIMIT 1;
隔离具有 "best" 匹配项的行。在使用和操作此结果行中最匹配的 data
之前,我使用 vSum
的大小为数据分配权重。
这非常有效。但是,我不是 SQL 专家,所以我不禁想知道是否可能没有 better/simpler/faster 方法来完成同样的事情。必须使用它的上下文不需要速度,所以我不热衷于使用更多存储和更多索引的权衡。如果有人能对我的方法发表评论并提出改进建议,我将不胜感激。
您可以通过一次计算分数将select转换为一个SELECT
语句。这消除了临时 table 和代码与数据库引擎之间的一些往返的需要:
select
*
, CASE WHEN (v0 = V0) THEN 1 ELSE 0 END
+CASE WHEN (v1 = V1) THEN 1 ELSE 0 END
+CASE WHEN (v2 = V1) THEN 1 ELSE 0 END
+CASE WHEN (v3 = V3) THEN 1 ELSE 0 END
+CASE WHEN (v4 = V4) THEN 1 ELSE 0 END
+CASE WHEN (v5 = V5) THEN 1 ELSE 0 END
+ ... as vSum
FROM valency
WHERE (typ = T)
AND (entity = E)
order by vSum desc
limit 1
您可能希望向 order by
子句添加更多条件,以确保您的顺序在运行之间保持一致。