Как сделать этот групповой запрос ActiveRecord в postgres
Я пытаюсь найти в таблице 3M всех пользователей с одинаковыми именами. Я прочитал что-то вроде этого, может сделать свое дело.
User.find(:all, :group => [:username], :having => "count(*) > 1" )
Однако, так как я использую Postgres, это возвращает меня ActiveRecord::StatementInvalid: PG::Error: ERROR: column "users.id" must appear in the GROUP BY clause or be used in an aggregate function
,
Я пытаюсь что-то вроде этого
User.select('users.id, users.username').having("count(*) > 1").group('users.username')
Но все равно получаю ту же ошибку. Есть идеи, что я делаю не так?
Обновление: я заставил это так или иначе работать, используя User.select('users.*').group('users.id').having('count(users.username) > 1')
но этот запрос возвращает мне это, которое выглядит как пустой массив, даже если найдено 5 записей.
GroupAggregate (cost=9781143.40..9843673.60 rows=3126510 width=1365)
Filter: (count(username) > 1)
-> Sort (cost=9781143.40..9788959.68 rows=3126510 width=1365)
Sort Key: id
-> Seq Scan on users (cost=0.00..146751.10 rows=3126510 width=1365)
(5 rows)
=> []
Любая идея, почему это происходит и как получить эти 5 строк?
2 ответа
Я думаю, что лучшее, что вы можете получить, это получить имена пользователей для дубликатов записей. Это может быть достигнуто с
User.select(:username).group(:username).having('COUNT(username) > 1')
"group by" в базе данных сворачивает каждую группу в одну строку в выходных данных. Скорее всего, то, что вы намереваетесь, будет получено с помощью следующего запроса:
User.where("name in (select name from users group by name having count(*)>1)").order(:name)
Внутренний запрос выше находит все имена, которые появляются более одного раза. Затем мы находим все строки с этими именами. Заказ по названию облегчит вашу дальнейшую обработку. Для ускорения добавьте индекс к имени столбца в таблице пользователей.
Существуют альтернативные способы решения этой проблемы со стороны Postgres, однако вышеперечисленное будет работать во всех базах данных.