mec*_*cov 4 ruby-on-rails common-table-expression rails-activerecord
通用表表达式是不同 RDBMS(PostgreSQL、MySQL、Oracle、SQLite3 等)中相当常见的做法,用于跨多个查询组件多次执行相同的计算或用于某些其他目的
我发现旧的 gem postgres_ext具有这样的功能。但它没有得到维护。这是 Postgres 特有的
有一些关于它的老问题,但它们是关于特定的 Rails 版本或特定的 RDBMS 或关于Arel
是否可以使用WITHAR 某种常见方式在 Rails 中使用子句?
mec*_*cov 10
在这个拉取请求之后,Rails 7.1 引入了with可以带几个参数的方法
假设我们有books一个带有整数reviews_count列的表。要定义和使用 CTE,您可以应用ActiveRecord::QueryMethods#with以下方式:
Book.with(books_with_reviews: Book.where("reviews_count > ?", 0))
# WITH books_with_reviews AS (
# SELECT * FROM books WHERE (reviews_count > 0)
# )
# SELECT * FROM books
Run Code Online (Sandbox Code Playgroud)
它返回ActiveRecord::Relation对象,这使得它的使用非常方便和灵活
例如,定义公共表表达式后,可以将辅助语句的名称与指定的FROM子句或JOIN语句一起使用:
Book
.with(books_with_reviews: Book.where("reviews_count > ?", 0))
.from("books_with_reviews AS books")
# WITH books_with_reviews AS (
# SELECT * FROM books WHERE (reviews_count > 0)
# )
# SELECT * FROM books_with_reviews AS books
Run Code Online (Sandbox Code Playgroud)
Book
.with(books_with_reviews: Book.where("reviews_count > ?", 0))
.joins("JOIN books_with_reviews ON books_with_reviews.id = books.id")
# WITH books_with_reviews AS (
# SELECT * FROM books WHERE (reviews_count > 0)
# )
# SELECT * FROM books JOIN books_with_reviews ON books_with_reviews.id = books.id
Run Code Online (Sandbox Code Playgroud)
也可以使用Arel.sql以下方法传递 SQL 查询:
Book.with(popular_books: Arel.sql("some SQL literals here"))
Run Code Online (Sandbox Code Playgroud)
重要提示:仔细检查此类参数以防止 SQL 注入漏洞,此方法不得与不安全值一起使用,尤其是那些包含未经消毒的输入的值
要定义多个 CTE,只需传递一些哈希值作为参数:
Book.with(
books_with_reviews: Book.where("reviews_count > ?", 0),
books_with_ratings: Book.where("ratings_count > ?", 0)
)
# WITH books_with_reviews AS (
# SELECT * FROM books WHERE (reviews_count > 0)
# ), books_with_ratings AS (
# SELECT * FROM books WHERE (ratings_count > 0)
# )
# SELECT * FROM books
Run Code Online (Sandbox Code Playgroud)
由于with返回关系,您可以简单地将其链接多次:
Book
.with(books_with_reviews: Book.where("reviews_count > ?", 0))
.with(books_with_ratings: Book.where("ratings_count > ?", 0))
# WITH books_with_reviews AS (
# SELECT * FROM books WHERE (reviews_count > 0)
# ), books_with_ratings AS (
# SELECT * FROM books WHERE (ratings_count > 0)
# )
# SELECT * FROM books
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1583 次 |
| 最近记录: |