【问题标题】:How to do this SQL query in Rails?如何在 Rails 中执行此 SQL 查询?
【发布时间】:2014-03-18 18:41:32
【问题描述】:

如何在 Rails 中进行这个 SQL 查询?

我正在尝试加入三个表。我很确定我已经在模型中正确连接了它们。

我有几个连接表,在这种情况下,有一个“所有权”表,其中包含用户 ID 和游戏 ID。它与“游戏”表和“用户”表进行内连接。游戏表有游戏信息,并有一个与控制台表连接的console 列。控制台表是数据库中的所有控制台。这样,当我展示一个游戏的时候,我就可以展示它所属的控制台了。

我创建了一个网络界面来跟上我的视频游戏收藏。我让它在 PHP 中工作,但我正在将所有内容都转换为 Ruby on Rails。我现在要做的是,在库存页面上,我想显示用户拥有游戏的控制台,以便用户可以选择一个控制台并过滤显示的游戏以仅显示该控制台的游戏。

例如,主库存页面会显示用户拥有的每款游戏。右侧有一个侧边栏,其中包含用户拥有游戏的控制台。如果用户只想查看他拥有的 N64 游戏,他点击 N64 并过滤显示以仅显示 N64 游戏。

我不想在侧边栏显示控制台,除非用户拥有该控制台的游戏。

这是我想要处理的 SQL 查询:

select distinct console_general.eng_name from ownership inner join games on games.id=ownership.games_id inner join console_general on console_general.console_id=games.console_general_id;

这是我的桌子:

mysql> describe games;
+--------------------+------------+------+-----+---------+----------------+
| Field              | Type       | Null | Key | Default | Extra          |
+--------------------+------------+------+-----+---------+----------------+
| id                 | int(11)    | NO   | PRI | NULL    | auto_increment |
| ean                | mediumtext | YES  |     | NULL    |                |
| eng_title          | mediumtext | YES  |     | NULL    |                |
| jap_title          | mediumtext | YES  |     | NULL    |                |
| console_general_id | int(11)    | YES  | MUL | NULL    |                |
| region_id          | int(11)    | YES  | MUL | NULL    |                |
| image              | int(11)    | YES  | MUL | NULL    |                |
+--------------------+------------+------+-----+---------+----------------+

mysql> describe ownership;
+----------------------+------------+------+-----+---------+-------+
| Field                | Type       | Null | Key | Default | Extra |
+----------------------+------------+------+-----+---------+-------+
| user_id              | int(11)    | NO   |     | 0       |       |
| games_id             | int(11)    | YES  | MUL | NULL    |       |
| own                  | tinyint(1) | YES  |     | NULL    |       |
| complete             | tinyint(1) | YES  |     | NULL    |       |
| box_condition        | int(11)    | YES  | MUL | NULL    |       |
| game_condition       | int(11)    | YES  | MUL | NULL    |       |
| manual_condition     | int(11)    | YES  | MUL | NULL    |       |
| inserts_condition    | int(11)    | YES  | MUL | NULL    |       |
| notes                | text       | YES  |     | NULL    |       |
| spine_card_condition | int(11)    | YES  | MUL | NULL    |       |
| count                | int(11)    | NO   |     | 1       |       |
+----------------------+------------+------+-----+---------+-------+

mysql> describe console_general
    -> ;
+------------+---------+------+-----+---------+----------------+
| Field      | Type    | Null | Key | Default | Extra          |
+------------+---------+------+-----+---------+----------------+
| console_id | int(11) | NO   | PRI | NULL    | auto_increment |
| eng_name   | text    | YES  |     | NULL    |                |
| jap_name   | text    | YES  |     | NULL    |                |
+------------+---------+------+-----+---------+----------------+

这是我的控制器:

class InventoryController < ApplicationController
  def test

    # These work fine
    @user = User.find_by(params[:id])
    @ownership = Ownership.where(user_id: 1)

    # This is the variable I've been working on, not sure if I'm on the right track or not.
    # @console =  Ownership.joins(games: {console_general: :console_id})
  end
end

这是我的模型:

class Ownership < ActiveRecord::Base
self.pluralize_table_names = false

belongs_to :games

Ownership.joins(:games)

end

class Games < ActiveRecord::Base
belongs_to :console_general
belongs_to :region
belongs_to :image
has_many :ownership

Games.joins(:region, :console_general, :image)
end

lass ConsoleGeneral < ActiveRecord::Base
self.pluralize_table_names = false

has_many :games
has_many :accessories
end

我希望这是有道理的。

编辑:

稍微处理一下给定的答案,我就能得到它。模型关联是正确的,但控制器实例变量一开始不起作用,这就是我所做的

Ownership.joins(:games => :console_general).uniq.pluck(:eng_name)

这很好用。感谢大家的帮助。

【问题讨论】:

    标签: sql ruby-on-rails ruby join controller


    【解决方案1】:
    class User < ActiveRecord::Base
      has_many :ownerships
      has_many :games, through: :ownerships
    end
    
    class Ownership < ActiveRecord::Base
      belongs_to :user
      belongs_to :game
    end
    
    class Game < ActiveRecord::Base
      has_many :ownerships
      has_many :users, through: :ownerships
      belongs_to :console_general
    end
    
    class ConsoleGeneral < ActiveRecord::Base
      has_many :games
    end
    

    Railsguide

    那么对于

    select distinct console_general.eng_name from ownership 
    inner join games ongames.id=ownership.games_id 
    inner join console_general on console_general.console_id=games.console_general_id
    

    ...如果这样做的目的是查看所有有游戏的游戏机,那么您可以这样做:

    ConsoleGenerals.joins(:games).uniq.pluck(:eng_name)
    

    pluck 只选择 eng_name,uniq 产生“select distinct”,joins(:games) 将强制存在相关游戏。

    或者如果您想限制为拥有的游戏,也可以这样做

    ConsoleGenerals.joins(:games => :ownerships).uniq.pluck(:eng_name)
    

    【讨论】:

    • 看来这就是我想去的地方。我现在遇到另一个错误:未初始化的常量 ConsoleGeneral::Game.but 至少它比另一个更好。想法?因为我是在现有数据库上构建的,所以我不知道我的表名是否会导致 rails 出现问题。
    • 知道了,稍微修改了你的代码,这就是我最终得到的 Ownership.joins(:games => :console_general).uniq.pluck(:eng_name)
    【解决方案2】:
    class ConsoleGeneral < ActiveRecord::Base
      ...
      scope :with_owned_games, -> { joins(:games).merge(Games.with_ownerships) }
    end
    
    class Games < ActiveRecord::Base
      ...
      scope :with_ownerships, -> { joins(:ownership) }
      scope :with_certain_owner, -> { |owner_id| joins(:ownership).where(user_id: owner_id) }
    end
    

    拥有游戏所有权的控制台:

    ConsoleGeneral.with_owned_games
    

    仅限Uniq eng_names:

    ConsoleGeneral.with_owned_games.select(:eng_name).uniq
    

    拥有属于 id = some_user_id 用户的游戏的控制台:

    ConsoleGeneral.with_certain_owner(some_user_id)
    

    仅限Uniq eng_names:

    ConsoleGeneral.with_certain_owner(some_user_id).select(:eng_name).uniq
    

    【讨论】:

    • 范围在这里是一个不错的选择。但是使用 select 而不是 pluck 来复制只有一列的查询明显较差。 Select 构建完整的活动模型,而 pluck 生成一个简单的结果数组。
    • 致elc:我确定你错了。 gistflow.com/posts/328-pluck-vs-select-again
    • 引用您链接到的页面--“不要忘记使用 pluck 时未完成的 AR 实例化的所有开销,这样在大型数据集上它的性能会更好“选择”解决方案”
    • 首先的问题是“如何执行此 SQL 查询...”(而不是“如何获取数组”)。
    • 正确。并且有问题的 SQL 查询只返回一列——这就是 pluck 所做的。如果它是“select *”,那么 rails 的 select 将是等效的。 array vs activerecord collect 无疑是一个后续,但它是密切相关的并且具有潜在的意义。
    猜你喜欢
    • 2021-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-15
    • 1970-01-01
    • 2017-09-28
    相关资源
    最近更新 更多