Поиск «лучшего частичного соответствия» в таблице SQLite без частичного индекса - PullRequest
0 голосов
/ 12 января 2019

В моем приложении для Android, которое использует SQLite для хранения пользовательских данных, у меня есть таблица с именем valency, как показано ниже.

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);

Мне нужно найти «лучшее» соответствие для строк в этой таблице для столбцов v0.. v5 для определенного значения для столбцов typ и entity. Чем больше совпадающих столбцов, тем больший вес я хочу прикрепить к соответствующему столбцу data.

Вот как я прохожу процесс

Шаг 1 - прочитать соответствующие строки в таблицу TEMP

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. Все, что меня действительно волнует, так это «лучшее» совпадение - то есть определение строка с наибольшим количеством ненулевых значений v*.

Шаг 3

SELECT urid,lato,data,v0 + v1 + v2 + v3 + v4 + v5 as 'vSum' FROM H1 ORDER BY vSum DESC LIMIT 1;

, который изолирует строку с "лучшим" соответствием. Прежде чем использовать и манипулировать наиболее подходящим data в этой строке результатов, я использую величину vSum, чтобы присвоить взвешивание данным.

Это работает - отлично. Тем не менее, я не эксперт по SQL, поэтому я не могу не задаться вопросом, не может ли быть лучшего / более простого / более быстрого способа сделать то же самое. Контекст, в котором это должно использоваться, не требует скорости, поэтому я не заинтересован в компромиссе, который использует больше памяти с большим количеством индексации. Я был бы очень признателен всем, кто мог бы прокомментировать мой подход и предложить улучшения.

1 Ответ

0 голосов
/ 12 января 2019

Вы можете преобразовать выбор в один оператор SELECT, вычисляя счет за один раз. Это устраняет необходимость во временной таблице и некоторых обходах между вашим кодом и механизмом базы данных:

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, чтобы убедиться, что ваш заказ остается согласованным между прогонами.

...