Сохраняйте только строки, в которых один столбец минимален

#sql #sqlite #join #sql-delete

#sql #sqlite #Присоединиться #sql-удалить

Вопрос:

Я ищу запрос SQLite, чтобы значительно уменьшить неуместный шум в моей базе данных. Соответствующая таблица содержит пары точек (‘hexbin’s) вместе с расстоянием между ними и источником, который задал это расстояние. Я хотел бы сохранить только строки для минимального расстояния, найденного в любом источнике для каждой пары точек.

Я думаю

 DELETE FROM dist
  WHERE hexbin1, hexbin2, source NOT IN (
    SELECT hexbin1, hexbin2, source FROM dist INNER JOIN (
      SELECT hexbin1 as h1, hexbin2 as h2, min(distance) as m
      FROM dist GROUP BY hexbin1, hexbin2)
    ON hexbin1==h1 AND hexbin2==h2 AND distance==m);
  

должно поступать примерно правильно.
Теоретически, у меня могут быть разные строки с одинаковыми hexbin1, hexbin2 и расстоянием, но разным источником. На практике это маловероятно и не является препятствием для следующих процессов, которым необходимо использовать базу данных, поэтому их можно сохранить или удалить в зависимости от того, что проще выполнить; мой запрос выше сохраняет дубликаты, но при прочих равных условиях я бы предпочел сохранить только один произвольный образец из всех с минимальным расстоянием.

Наивно читать, он выполняет итерацию по таблице три раза, что звучит неудобно. Как я могу сделать это лучше?

Комментарии:

1. Возможно ли, чтобы комбинация hexbin1, hexbin2 имела повторяющиеся расстояния, поэтому минимальное расстояние существует более чем в 1 строке?

2. Теоретически, у меня могут быть разные строки с одинаковыми hexbin1, hexbin2 и расстоянием, но разным источником. На практике это маловероятно и не является препятствием для следующих процессов, которым необходимо использовать базу данных, поэтому их можно сохранить или удалить в зависимости от того, что проще сделать.

Ответ №1:

Этот запрос:

 SELECT hexbin1, hexbin2, MIN(distance)
FROM dist d
GROUP BY hexbin1, hexbin2
  

возвращает все минимальные расстояния для каждой комбинации hexbin1, hexbin2 .
Если нет случая повторяющихся минимальных расстояний, вы можете использовать его следующим образом:

 DELETE FROM dist
WHERE (hexbin1, hexbin2, distance) NOT IN (
  SELECT hexbin1, hexbin2, MIN(distance)
  FROM dist 
  GROUP BY hexbin1, hexbin2
)
  

Смотрите упрощенную демонстрацию.

Но если есть дубликаты, то прерывателем связи может быть столбец rowid с помощью FIRST_VALUE() оконной функции:

 DELETE FROM dist
WHERE rowid NOT IN (
  SELECT FIRST_VALUE(rowid) OVER (PARTITION BY hexbin1, hexbin2 ORDER BY distance, rowid)
  FROM dist
)
  

Смотрите упрощенную демонстрацию.

Ответ №2:

Вы можете попробовать:

 delete from dist
    where exists (select 1
                  from dest d2
                  where d2.hexbin1 = d.hexbin1 and d2.hexbin2 = d.hexbin2 and d2.distance > d.distance
                 );
  

В частности, это может использовать преимущество индекса на (hexbin1, hexbin2, distance) .