我的用户有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
有没有更好的方式
答案 0 :(得分:33)
通过首先找出重复数据的内容,您可以大大缩小搜索范围。例如,假设您要查找多次使用的名字和电子邮件的每个组合。
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")
答案 1 :(得分:0)
经过一些谷歌搜索后,我最终得到了这个:
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中的等号进行比较。
答案 2 :(得分:0)
如果您要使用@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
请阅读Clarify DataBaseStatements#execute以深入了解问题。