Поиск всех пользователей с одинаковыми именами - PullRequest
14 голосов
/ 30 декабря 2010

У меня есть пользователи, у которых есть поля first_name и last_name, и мне нужно сделать ruby, чтобы найти всех пользователей, которые имеют дубликаты аккаунтов на основе имени и фамилии. Например, мне нужна находка, которая будет искать среди всех других пользователей и находить, имеют ли они такое же имя и адрес электронной почты. Я думал, что вложенный цикл, как это

User.all.each do |user|
 //maybe another loop to search through all the users and maybe if a match occurs put that user in an array
end

Есть ли лучший способ

Ответы [ 3 ]

33 голосов
/ 30 декабря 2010

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

User.find(:all, :group => [:first, :email], :having => "count(*) > 1" )

Это вернет массив, содержащий одну из каждой дублированной записи.Исходя из этого, скажем, у одного из возвращенных пользователей были «Fred» и «fred@example.com», тогда вы можете искать только тех пользователей, у которых есть эти значения, чтобы найти всех затронутых пользователей.

Возвращение от этого find будет что-то вроде следующего.Обратите внимание, что массив содержит только одну запись из каждого набора дублированных пользователей.

[#<User id: 3, first: "foo", last: "barney", email: "foo@example.com", created_at: "2010-12-30 17:14:43", updated_at: "2010-12-30 17:14:43">, 
 #<User id: 5, first: "foo1", last: "baasdasdr", email: "abc@example.com", created_at: "2010-12-30 17:20:49", updated_at: "2010-12-30 17:20:49">]

Например, первый элемент в этом массиве показывает одного пользователя с "foo" и "foo@example.com".Остальные из них могут быть извлечены из базы данных по мере необходимости с помощью поиска.

> User.find(:all, :conditions => {:email => "foo@example.com", :first => "foo"})
 => [#<User id: 1, first: "foo", last: "bar", email: "foo@example.com", created_at: "2010-12-30 17:14:28", updated_at: "2010-12-30 17:14:28">, 
     #<User id: 3, first: "foo", last: "barney", email: "foo@example.com", created_at: "2010-12-30 17:14:43", updated_at: "2010-12-30 17:14:43">]

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

Редактировать:

Если вам нужно использовать большой молот find_by_sql, потому что Rails 2.2 и более ранние версии не поддерживали :having с find,следующее должно работать и дать вам тот же массив, который я описал выше.

User.find_by_sql("select * from users group by first,email having count(*) > 1")
0 голосов
/ 12 мая 2017

Если вы идете по маршруту @hakunin и создаете запрос вручную, вы можете использовать следующее:

ActiveRecord::Base.connection.exec_quey(<<-SQL).to_a
  SELECT 
    variants.id, variants.variant_no, variants.state 
  FROM variants INNER JOIN (
    SELECT 
      variant_no, state, COUNT(1) AS count 
    FROM variants
    GROUP BY 
      variant_no, state HAVING COUNT(1) > 1
  ) tt ON 
    variants.variant_no = tt.variant_no 
    AND variants.state IS NOT DISTINCT FROM tt.state;
SQL

Изменение заменяет connection.execute(<<-SQL) на connection.exec_query(<<-SQL)

Возможна проблема с утечкой памяти при использовании execute

Просьба прочитать Уточнение DataBaseStatements # выполнить для более глубокого понимания проблемы.

0 голосов
/ 23 июня 2015

После некоторого поиска в Google я получил следующее:

ActiveRecord::Base.connection.execute(<<-SQL).to_a
  SELECT 
    variants.id, variants.variant_no, variants.state 
  FROM variants INNER JOIN (
    SELECT 
      variant_no, state, COUNT(1) AS count 
    FROM variants
    GROUP BY 
      variant_no, state HAVING COUNT(1) > 1
  ) tt ON 
    variants.variant_no = tt.variant_no 
    AND variants.state IS NOT DISTINCT FROM tt.state;
SQL

Обратите внимание, что часть с надписью IS NOT DISTINCT FROM предназначена для помощи NULL значениям, которые нельзя сравнить со знаком равенства в postgres.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...