假设我有一个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
我从自定义生成的表中进行选择。我怎么会开始写这个查询?这甚至可能吗?如果是这样,如果没有,我的替代方案是什么?
谢谢!
答案 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")