如何在初始 where 语句中使用 Arel::Nodes::TableAlias
Posted
技术标签:
【中文标题】如何在初始 where 语句中使用 Arel::Nodes::TableAlias【英文标题】:How to use Arel::Nodes::TableAlias in an initial where statement 【发布时间】:2014-06-24 02:54:39 【问题描述】:我被困在这个问题上,当然这很容易,但我只是在文档中找不到解决方案。
我有一些树结构和子 where 子句,我必须使用“存在”子查询进行过滤:
current_node.children.as("children_nodes").where(Node.where(...).exists)
Node.where.clause 已经加入 children_nodes,如果我使用两种不同的模型,它就可以工作。但是如何使用别名?以上代码将导致:
NoMethodError (undefined method `where' for #<Arel::Nodes::TableAlias
它是如此基本,但我缺少一些东西(我对 arel 太陌生了)。
【问题讨论】:
尝试current_node.children.as("children_nodes").Node.(where(...).exists)
并没有测试。
current_node.children.as("children_nodes").Node 将为我提供 #<:nodes::tablealias node>
【参考方案1】:
您也许可以使用属性table_alias
,您可以在 Arel::Table 上调用它。
例子:
# works
users = User.arel_table
some_other_table = Post.arel_table
users.table_alias = 'people'
users.join(some_other_table)
# doesn't work
users = User.arel_table.alias('people')
some_other_table = Post.arel_table
users.join(some_other_table)
【讨论】:
警告:arel_table
方法总是返回相同的对象(至少在 Rails 4.2 中),所以更改 table_alias
有副作用。使用 User.arel_table.dup
效果很好。【参考方案2】:
as 方法生成一个没有 where 方法如 Relation 对象的 arel 对象 Arel 对象生成一个要执行的 sql,基本上它是一个选择管理器 你可以使用 union 并给它另一个条件,然后使用 to_sql 例如:
arel_obj = current_node.children.as("children_nodes").Union(Node.where(....)
sql_string = arel_obj.to_sql
Node.find_by_sql(sql_string)
这里有一些可能有帮助的链接 http://www.rubydoc.info/github/rails/arel/Arel/SelectManager
【讨论】:
【参考方案3】:在 Arel 中,as
将使用该点的所有内容并使用它来创建一个命名子查询,您可以将其放入 FROM
子句中。例如,current_node.children.as("children_nodes").to_sql
将打印如下内容:
(SELECT nodes.* FROM nodes WHERE nodes.parent_id = 5) AS children_nodes
但听起来您真正想要的是为nodes
表提供SQL 别名。从技术上讲,您可以使用from
:
current_node.children.from("nodes AS children_nodes").to_sql
但是如果你这样做了,很多其他的事情都会被破坏,因为查询的其余部分仍在尝试SELECT nodes.*
和过滤WHERE nodes.parent_id = 5
。
所以我认为更好的选择是避免使用别名,或者使用find_by_sql
编写查询:
Node.find_by_sql <<-EOQ
SELECT n.*
FROM nodes n
WHERE n.parent_id = 5
AND EXISTS (SELECT 1
FROM nodes n2
WHERE ....)
EOQ
也许您也可以通过给内部表起别名来使事情正常进行:
current_node.children.where(
Node.from("nodes n").where("...").select("1").exists
)
【讨论】:
以上是关于如何在初始 where 语句中使用 Arel::Nodes::TableAlias的主要内容,如果未能解决你的问题,请参考以下文章
如何在 switch 语句中使用 laravel 模型运行多个 Where 子句