Подтвердить что ты не робот

Поиск всех пользователей, имеющих дубликаты имен

У меня есть пользователи, у которых есть поля 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

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

4b9b3361

Ответ 1

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

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

Это вернет массив, содержащий одну из каждой из дублированных записей. Из этого следует, что один из возвращаемых пользователей имел "Fred" и "[email protected]", тогда вы могли искать только тех пользователей, у которых есть эти значения, чтобы найти всех затронутых пользователей.

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

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

Например, первый элемент в этом массиве показывает одного пользователя с "foo" и "[email protected]". Остальные из них можно вытащить из базы данных по мере необходимости с помощью find.

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

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

Edit:

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

User.find_by_sql("select * from users group by first,email having count(*) > 1")

Ответ 2

После некоторого googling я закончил с этим:

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.

Ответ 3

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