首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否有方法为Activerecord中的单个查询创建临时列?

是否有方法为Activerecord中的单个查询创建临时列?
EN

Stack Overflow用户
提问于 2019-11-30 19:01:45
回答 3查看 851关注 0票数 0

假设我们有一个具有以下迁移的ChessPiece类。

代码语言:javascript
复制
create_table :chess_pieces do |t|
  t.string  :type
  t.integer :row
  t.integer :column
  t.integer :game_id, index: true
end

如果一个主教想要从(0,0)移动到(7,7),那么我需要检查两个位置之间的每个空格,以寻找其他可能阻塞我的主教的部分。如果有一个当铺(5,5)。

我可以查询数据库中可能有如下阻塞部分的每个位置:

代码语言:javascript
复制
pieces = []
8.times do |i|
  pieces << ChessPiece.where(game_id: @game_id, row: i, column: i)
end

但我想减少查询。或者,我可以为一个游戏抓取所有的棋子,并在中迭代它们,但这似乎也没有效率。我想要做的是告诉数据库将rowcolumn列组合到表单“row-列”中,并称之为position。这样我就可以运行类似于以下查询的内容:

代码语言:javascript
复制
ChessPiece.where(game_id: @game_id, position: ["1-1", "2-2", "3-3"])

如何动态创建这个新列,以便运行类似于上述查询的内容?(假设我不能只编辑数据库模式。)

EN

回答 3

Stack Overflow用户

发布于 2019-11-30 20:17:56

可以使用.select创建所需的任意select语句:

代码语言:javascript
复制
@chess_pieces = ChessPiece.select(
  "chess_pieces.*", 
  "CONCAT(chess_pieces.row, '-', chess_pieces.column) AS position"
)

使用别名时,结果中的列将作为模型上的一个属性可用:

代码语言:javascript
复制
@chess_pieces.first.position

您还可以在WHERE、ORDER和GROUP子句中使用列别名(PG、MySQL),但不是所有dbs:

代码语言:javascript
复制
ChessPiece.select(
  "chess_pieces.*", 
  "CONCAT(chess_pieces.row, '-', chess_pieces.column) AS position"
).where('position = ?', '1-1')
 .group('position')
 .order('position ASC')

对于那些不支持它的人,你需要把它连接起来,聚集起来,或者不管你在原地做什么。

代码语言:javascript
复制
ChessPiece.order("CONCAT(chess_pieces.row, '-', chess_pieces.column)")
票数 1
EN

Stack Overflow用户

发布于 2019-12-01 00:34:40

为什么不把这作为一个永久的专栏呢?

添加类型为整型的位置列。创建一个将位置设置为row * 10 + column的预保存钩子

现在可以查询“职位”列。

代码语言:javascript
复制
ChessPiece.where(game_id: @game_id, position: [11, 22, 33])

如果需要,还可以重写position=来设置列和行。允许您在写作中使用它。

票数 0
EN

Stack Overflow用户

发布于 2019-12-02 17:31:49

您可以向ChessPiece模型中添加一个助手,以简化构建正确的查询。像这样的事情应该能起作用:

代码语言:javascript
复制
class ChessPiece < ApplicationRecord
  def self.matches_position(*positions)
    return none if positions.empty?

    constraints = positions.map do |row, column|
      arel_table[:row].eq(row).and(arel_table[:column].eq(column))
    end

    where(constraints.reduce(:or))
  end
end

ChessPiece.where(game_id: @game_id).matches_position([1, 1], [2, 2], [3, 3])

这将导致SQL (根据所使用的数据库语法可能有所不同):

代码语言:javascript
复制
SELECT "chess_pieces".*
FROM "chess_pieces"
WHERE "chess_pieces"."game_id" = 1
  AND ("chess_pieces"."row" = 1 AND "chess_pieces"."column" = 1
       OR "chess_pieces"."row" = 2 AND "chess_pieces"."column" = 2
       OR "chess_pieces"."row" = 3 AND "chess_pieces"."column" = 3)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59119289

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档