【问题标题】:How to write this query in activerecord?如何在 activerecord 中编写此查询?
【发布时间】:2013-09-18 13:26:03
【问题描述】:

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

我正在从自定义生成的表格中进行选择。我什至如何开始编写这个查询?这甚至可能吗?如果是,如何,如果不是,我的替代方案是什么?

谢谢!

【问题讨论】:

  • 您在寻找什么结果?在您的查询中,您将返回所有用户名为 LIKE 'r%' 的用户,因为查询第一部分的所有结果也将在查询的第二部分中。您需要解释您希望查询返回的内容,因为您的查询不清楚。
  • 只是指出,查询结果集在那里是不确定的,除非您添加 ORDER BY 子句来补充每个 LIMIT 子句

标签: mysql ruby-on-rails ruby activerecord


【解决方案1】:

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

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

【讨论】:

  • 谢谢,一旦我进入我的开发环境,我会测试/通知你。
【解决方案2】:

看起来您只想获取包含十个用户的列表,其中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

【讨论】:

  • 谢谢,这是我以前用的,很慢。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    我觉得你可以用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")
    

    【讨论】:

    • 但是很抱歉,我还没有测试过。我的系统中没有安装mysqlrails。请帮助自己:)
    猜你喜欢
    • 1970-01-01
    • 2017-08-04
    • 2017-07-26
    • 1970-01-01
    • 2011-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多