пытаясь удалить повторяющиеся записи в базе данных, но получая нулевой идентификатор - PullRequest
0 голосов
/ 14 мая 2019

Я использую запрос rails find_by_sql для поиска дублирующихся записей, но у меня ужасное время при их удалении, потому что запрос возвращает массив с идентификаторами, указанными как nil.

LogEntry.find_by_sql("SELECT date, athlete_id, count(*) as qty FROM log_entries GROUP BY date, athlete_id HAVING count(*)> 1")

Возвращает следующий массив:

[#<LogEntry id: nil, date: "2016-06-12", athlete_id: 49>, #<LogEntry id: nil, date: "2015-09-05", athlete_id: nil>, #<LogEntry id: nil, date: "2015-09-06", athlete_id: nil>, #<LogEntry id: nil, date: "2019-05-02", athlete_id: nil>]

Когда я пытаюсь добавить .each(&:destroy), ему не удается его уничтожить, потому что, как вы видите, идентификаторы указаны как ноль. Чего я не понимаю, так это того, как это возможно? Записи должны быть в состоянии существовать в таблице без идентификаторов. Есть ли проблема с моим SQL-запросом?

Спасибо!

1 Ответ

5 голосов
/ 14 мая 2019

Обновленный ответ после комментария @ Engineeringmnky (спасибо, пропустил группировку).

Чтобы удалить дубликаты, вам необходимо получить идентификаторы дубликатов строк. Для каждого дубликата вам понадобится N - 1 идентификаторов, так как один должен быть оставлен позади.

Чтобы получить все идентификаторы для каждой группы, которая имеет более одного (и, следовательно, имеет дубликаты):

SELECT array_agg(id) FROM log_entries GROUP BY date, athlete_id HAVING count(*) > 1

Давайте пропустим первый идентификатор в каждой группе:

SELECT (array_agg(id))[2:] FROM log_entries GROUP BY date, athlete_id HAVING count(*) > 1

Далее нам нужно их откатить, чтобы получить список только тех идентификаторов, которые мы хотим удалить:

SELECT unnest((array_agg(id))[2:]) FROM log_entries GROUP BY date, athlete_id HAVING count(*) > 1

Теперь, чтобы загрузить их в Rails, достаточно простого .where(..), если идентификатор находится в созданном выше наборе результатов:

LogEntry.where('id IN (SELECT unnest((array_agg(id))[2:]) FROM log_entries GROUP BY date, athlete_id HAVING count(*) > 1)')

Оригинальный ответ:

Ваш SELECT не выбирает id. Добавьте id к вашему запросу, и оно должно работать:

LogEntry.find_by_sql("SELECT id, date, athlete_id, count(*) as qty FROM log_entries GROUP BY date, athlete_id HAVING count(*)> 1")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...