使用Rails ActiveRecord和公共表达式(CTE)

3

常用表达式是在不同的关系型数据库(如PostgreSQL,MySQL,Oracle,SQLite3等)中进行相同计算多次运算或出于其他目的而进行的常见实践。

我发现旧宝石postgres_ext具有此功能。 但它未得到维护。 而且它是Postgres特定的

有一些旧问题涉及特定的Rails版本或特定的关系型数据库或涉及Arel

是否有可能以一种常见的方式在Rails中使用WITH子句?


你真正的意思是“使用ActiveRecord查询接口”,它提供了漂亮的抽象,用于生成SQL。即使你使用Arel或SQL字符串编写查询,它们仍然通过AR。 - max
@max 我想你明白我在说什么,只是我不知道如何更好地表达它。 - mechnicov
我做了 - 这有点吹毛求疵。 - max
1个回答

8
Rails 7.1 介绍 with 方法
该方法返回 ActiveRecord::Relation
Post.with(posts_with_tags: Post.where("tags_count > ?", 0))
# WITH posts_with_tags AS (
#   SELECT * FROM posts WHERE (tags_count > 0)
# )
# SELECT * FROM posts

一旦您定义了公共表达式,就可以使用自定义的FROM值或JOIN来引用它。
Post.with(posts_with_tags: Post.where("tags_count > ?", 0)).from("posts_with_tags AS posts")
# WITH posts_with_tags AS (
#  SELECT * FROM posts WHERE (tags_count > 0)
# )
# SELECT * FROM posts_with_tags AS posts

Post.with(posts_with_tags: Post.where("tags_count > ?", 0)).joins("JOIN posts_with_tags ON posts_with_tags.id = posts.id")
# WITH posts_with_tags AS (
#   SELECT * FROM posts WHERE (tags_count > 0)
# )
# SELECT * FROM posts JOIN posts_with_tags ON posts_with_tags.id = posts.id

可以使用 Arel 传递不仅是 AR,而且是 SQL 字面值。
注:应该非常谨慎,以避免 SQL 注入漏洞。此方法不应与包括未经过滤的输入的不安全值一起使用。
Post.with(popular_posts: Arel.sql("... complex sql to calculate posts popularity ..."))

"要添加多个公共表表达式(CTE),只需传递多个键值对即可。"
Post.with(
  posts_with_comments: Post.where("comments_count > ?", 0),
  posts_with_tags: Post.where("tags_count > ?", 0)
)

或者链式多次调用 .with
Post
  .with(posts_with_comments: Post.where("comments_count > ?", 0))
  .with(posts_with_tags: Post.where("tags_count > ?", 0))

杀手级功能! - Ben
这很好。有没有一种适当的方式来根据需要指定“已实现”或“未实现”? - undefined
@theycallmethesloth 目前只有 Arel 支持此功能。这里有一个“常规” AR 非合并功能 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接