5

假设我有一个 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

4 回答 4

0

Ifusers 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 查询。单个查询的选项是执行外部联接,这对您的情况来说似乎很慢。

于 2013-09-19T06:41:36.617 回答
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")
于 2013-09-19T08:06:35.880 回答
0

看起来您只想获取包含 10 个用户的列表,其中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
于 2013-09-18T17:30:04.873 回答
0

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

基于那个 UNION 实现,我认为这应该可以解决问题:

# 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:忘记限制

于 2013-09-18T14:21:16.003 回答