【问题标题】:how to select fields from joined table properly?如何正确地从连接表中选择字段?
【发布时间】:2016-10-14 06:30:59
【问题描述】:

这是我的简化模型,我加入了模型,

样板房

   has_many :towers

模型塔

   belong_to :apartment

然后我尝试在控制器中加入两个表,也尝试在 Rails 控制台中这样:

Apartment.joins(:towers).select('apartments.id', 'apartments.name', 'towers.id' , 'towers.name')

问题是上面的查询只返回

apartments.id 和 apartments.name

也试过这样使用别名,还是不行

Apartment.joins(:towers).select('apartments.id', 'apartments.name', 'towers.id as towerid' , 'towers.name as towername')

我已确认所有塔楼都有公寓,我知道我可以这样做以获得 1 条记录

Apartment.joins(:towers).select('apartments.id', 'apartments.name', 'towers.id' , 'towers.name').first.towers.id

等等,但我需要所有记录和所有这些字段,请指教。

这是我在 Rails 控制台中得到的最新结果:

 Apt Load (1.0ms)  SELECT apts.id, apts.apt_name, towers.id as towerid, towers.
    tower_name as towername FROM `apts` INNER JOIN `towers` ON `towers`.`apt_id` = `
    apts`.`id`
    => #<ActiveRecord::Relation [#<Apt id: 5, apt_name: "basura">, #<Apt id: 5, apt_
    name: "basura">, #<Apt id: 124, apt_name: "hydra">, #<Apt id: 124, apt_name: "hy
    dra">, #<Apt id: 126, apt_name: "mediterania">, #<Apt id: 126, apt_name: "mediterania">, #<Apt id: 142, apt_name: "apartement gajah mada">, #<Apt id: 142, apt_name: "apartement gajah mada">]>

如您所见,上面的查询只返回 2 个字段,我需要这样的结果:

#<Apt id: 126, apt_name: "mediterania", tower_id: 12, tower_name: "tower A">, 
#<Apt id: 126, apt_name: "mediterania", tower_id: 15, tower_name: "tower F">

等...

【问题讨论】:

  • 使用 'includes' 代替 'joins'
  • 仅供参考。 first.towers.id 不起作用你必须写 first.towers.first.id
  • @GauravGupta 尝试在 Rails 控制台中使用包含,它抛出错误“未知列'towers.tower_name'”
  • @HendraLim 它不起作用,因为 towers 是 activerecord 关系你必须做 towers.first.name
  • @Dinesh 不会只返回一条记录吗?您能否在答案部分中提供您建议的完整示例。

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


【解决方案1】:

我认为这是可能的唯一方法是使用as

q = Apartment.joins(:towers).select('apartments.id, apartments.name, towers.id as t_id, towers.name as t_name')

q.first.t_id
q.first.t_name

为什么 first.towers.id 不起作用?

apartment.towers 将返回 ActiveRecord::Associations::CollectionProxy。您可以将其视为塔的集合。在 SQL 查询中,您指的是 towers 表。但是,当您运行 apartment.towers.id 时,您正在调用 CollectionProxy 对象上的 id ,这将不起作用。您可以使用towers.first 获得第一座塔。

关于,

Apt Load (1.0ms)  SELECT apts.id, apts.apt_name, towers.id as towerid, towers.
    tower_name as towername FROM `apts` INNER JOIN `towers` ON `towers`.`apt_id` = `
    apts`.`id`
    => #<ActiveRecord::Relation [#<Apt id: 5, apt_name: "basura">, #<Apt id: 5, apt_
    name: "basura">, #<Apt id: 124, apt_name: "hydra">, #<Apt id: 124, apt_name: "hy
    dra">, #<Apt id: 126, apt_name: "mediterania">, #<Apt id: 126, apt_name: "mediterania">, #<Apt id: 142, apt_name: "apartement gajah mada">, #<Apt id: 142, apt_name: "apartement gajah mada">]>

您在控制台看到的是inspsect 方法返回的结果。 inspect 方法并非旨在显示非列属性。因此,即使您在内存中有 towername,它也只会显示属于 Apartment 模型列的属性。 更多关于inspect

我还建议尝试以下操作:

Apartment.joins(:towers).pluck('apartments.id, apartments.name, towers.id as t_id, towers.name as t_name')

以上语句将获取数组中的所有数据。使用 select 得到的结果相同,但 select 不会加载数组中的所有数据。

【讨论】:

  • 确实返回了塔名,但问题是它只返回 1 条记录,我需要返回这样的数据 , # etc.
  • @HendraLim 随心所欲。在控制台中,它将仅显示 Apt 模型中存在的列。
  • 我以前用过 pluck,但是因为它返回一个数组而不是 ORM 对象,所以它不能解决我的问题,顺便说一句我已经解决了我的问题,我想你是对的我仍然可以访问 tower name 和 id 字段,即使它没有显示在控制台中,点赞,感谢您的帮助。
【解决方案2】:

你应该使用

Apartment.joins(:towers).select('apartments.id, apartments.name, towers.id , towers.name')

这是单个字符串中的所有列名。

Refer this.

【讨论】:

  • 你能发布生成的sql查询吗?或者如果您在控制台中尝试,只需在末尾添加 .to_sql 并查看它是否生成正确的查询。
  • 给你 : => "SELECT apts.id, apts.apt_name, towers.id, tower.tower_name FROM apts INNER JOIN towers ON towers.apt_id = @ 987654328@.id"
  • 这有点奇怪,因为我可以看到查询是正确生成的,但不知何故,查询结果并没有反映出来。哦,顺便说一句,我还尝试使用我的第一种方法检查生成的查询,所有字段都在分隔字符串中,它也返回与您的方法相同的查询。
  • 是的,很奇怪。顺便说一句,您是否编辑了结果并将apartments 替换为apts 或者您的表名是这样的?如果有的话,你可以直接通过mysql控制台或phpMyAdmin之类的任何GUI运行这个查询,看看它是否正确返回结果。
  • 实际上是我的真实模型命名为 apts,但为了使其更易于理解,所以我将其写为公寓,我确实在我的 sql 工作台中运行了生成的查询,结果正是我需要的,但不知何故,它在 Rails 中不起作用。
【解决方案3】:

你可以试试下面的别名

Apartment.joins(:towers).select('apartments.id as apartment_id, apartments.name as apartment_name, towers.id as tower_id , towers.name as tower_name)

【讨论】:

  • 试试这个。 Apartment.joins("OUTER JOIN towers on towers.apartment_id = apartments.id").select('apartments.id as apartment_id, apartments.name as apartment_name, towers.id as tower_id , towers.name 为 tower_name)
【解决方案4】:

你可以试试这个

Apartment.joins(:towers).select('apartments.id 为 id, apartments.name 为 apartment_name, towers.id 为 tower_id , towers.name 为 tower_name)

你会得到这样的回应 #ActiveRecord::Relation [#, #]>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-11
    • 1970-01-01
    相关资源
    最近更新 更多