如何在activerecord中编写此查询?

时间:2013-09-18 13:26:03

标签: mysql ruby-on-rails ruby activerecord

假设我有一个ActiveRecord :: Base子类User和表users,我不知道如何在ActiveRecord中编写此查询:

SELECT *
FROM (
    SELECT users.* 
    FROM   follows
    INNER JOIN users ON users.id = follows.following_id
    WHERE  username LIKE 'r%' AND follows.follower_id = 5717
    LIMIT 10

    UNION

    SELECT * 
    FROM   users 
    WHERE  username LIKE 'r%' 
    LIMIT 10
) AS users
LIMIT 10

我从自定义生成的表中进行选择。我怎么会开始写这个查询?这甚至可能吗?如果是这样,如果没有,我的替代方案是什么?

谢谢!

4 个答案:

答案 0 :(得分:0)

谢谢,这是一个有趣的问题。

根据that UNION implementation,我认为这应该可以解决问题:

# first sub query, inversed compared to your's, so that we get user fields
followed = User.group( 'users.id, users.username, follows.follower_id' ).having( "users.username like 'r%' and follows.follower_id = 5717" ).joins( :follows )

# second sub query
user = User.where( "username like 'r%'" )

# joining both using union
related_people_query = [ followed, user ].map { |query| query.select( 'users.id' ).to_sql }.join( ' UNION ' )
related_people = User.where( "users.id IN (#{related_people_query)" ).limit(10)

当然,这是一个大问题,我无法测试,所以我很想知道它是否适合你。

编辑:我在第一个子查询上忘了#joins

编辑2:忘记限制

答案 1 :(得分:0)

看起来您只想获得十个用户的列表,其中username like '%r'(必填)和follows.follower_id = 5717(首选)。如果是这种情况,请尝试以下方法(拆分易读性;未经测试):

User
  .joins("LEFT OUTER JOIN follows ON users.id = follows.following_id")
  .where("username like 'r%'")
  .order('follows.follower_id = 5717 desc, rand()')
  .limit(10)
  .uniq

答案 2 :(得分:0)

如果users with username LIKE r%是一小组记录。我会用急切的加载

users = User
        # get all users with matching username and all the associated follows
       .where("username LIKE 'r%' ").includes(:follows)
        # arrange the records in ruby  to get users with given follower id first
       .sort{|x|  x.follows.map(&:follower_id).include?(5717) ? 0 : 1 }
        # return first 10 records
       .first(10)

否则我会使用交错的方法

# try to get 10 records with matching username and follower_id using an inner join
users  = User.joins(:follows).where("username LIKE 'r%' AND follows.follower_id = ?", 5717).group("users.id").limit(10)

# if less than 10 records found, run second query to get users with matching records only
users += User.where(" username LIKE 'r%' AND id NOT IN (?)", users.map(&:id)).limit(10-user.count) if users.count < 10

上述两种方法都会产生2个SQL查询。单个查询的选项是执行外连接,这对您的情况来说似乎很慢。

答案 3 :(得分:0)

我认为您可以使用find_by_sql来实现此类复杂的查询

User.find_by_sql("SELECT * FROM (SELECT users.* FROM   follows INNER JOIN users ON users.id = follows.following_id WHERE  username LIKE 'r%' AND follows.follower_id = 5717 LIMIT 10 UNION SELECT * FROM   users WHERE  username LIKE 'r%' LIMIT 10) AS users LIMIT 10")