【问题标题】:Rails/SQL: Using an array as a search parameterRails/SQL:使用数组作为搜索参数
【发布时间】:2016-07-29 20:17:43
【问题描述】:

在电子商务商店应用程序中,我想检索与通过搜索表单输入的 first_name 匹配且已付款 == true 的所有订单。搜索表单通过参数Parameters: {"utf8"=>"✓", "search"=>"john", "commit"=>"Search"} 提交搜索词。在控制器中

@users = User.search(params[:search]) #returns all users with the matching first_name, e.g. 'john'
@order = Order.where('user_id = ? AND paid = ?',  @users.ids, true )

@order 中的查询工作正常,如果只返回一个 user,例如只有一位用户名为 john。但如果多个用户名为 John,则返回多个用户 ID,并返回错误消息 ActiveRecord::StatementInvalid。我的理解是,一旦`@users.ids 是一个具有多个值的数组,查询就会停止工作。

我如何构建以下查询:对于每个 user_id,返回所有已付款等于 true 的订单 (user.orders)。

Models
user.rb
has_many :orders

order.rb
belongs_to :users

【问题讨论】:

    标签: sql ruby-on-rails postgresql ruby-on-rails-4 rails-activerecord


    【解决方案1】:

    有多种方法可以解决这个问题。

    您可以按照Nic Nilov 的建议使用 JOIN,但如果您的 @users 查询是使用范围构建的并且您不想手动内联这些范围,这可能会很困难。

    您也可以使用子查询,因为 Rails4 中的 ActiveRecord 足够聪明,当您在 where 中使用关系时,您只需使用 where 的哈希形式即可:

    @users = User.search(params[:search])
    # @users should be a User::ActiveRecord_Relation now.
    @orders = Order.where(:user_id => @users, :paid => true)
    

    这将以如下 SQL 结束:

    select *
    from orders
    where paid = 't'
      and user_id in (
        select id
        from users
        where /* whatever `search` does... */
    )
    

    这里的好处是你不需要知道User.search 做了什么,只要它返回一个 ActiveRecord 关系。

    如果您的 @users 实际上是一个数组(由 ids 或整个 User 实例组成),那么您将采用完全相同的方式:

    # Suppose @users is an array of Users or an array of User ids...
    @orders = Order.where(:user_id => @users, :paid => true)
    

    ActiveRecord 将弄清楚如何处理您的 @users 数组,而无需您做任何额外的事情。

    【讨论】:

      【解决方案2】:

      您应该使用带有WHERE IN 子句的嵌套查询,而不是两个查询

      SELECT * from Order WHERE user_id IN (SELECT user_id FROM users WHERE first_name LIKE ?) AND paid = true
      

      【讨论】:

        【解决方案3】:

        应该这样做:

        Order.joins(:user).where(users: { name: params[:search] }, paid: true)
        

        它会生成一个带有 INNER JOIN 的查询:

        SELECT "orders".*
          FROM "orders"
            INNER JOIN "users" ON "users"."id" = "orders"."user_id"
          WHERE "users"."name" = 'Test User' AND "orders"."paid" = 't'
        

        【讨论】:

        • 这里的问题是你假设User.search(s) 真的是User.where(:name => s) 而不是,比如说,一个LIKE 查询。
        猜你喜欢
        • 1970-01-01
        • 2012-09-16
        • 1970-01-01
        • 2012-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-17
        相关资源
        最近更新 更多