我在rails中有3个模型:Author,Book和Page。页面属于书籍,书籍属于作者:
from pyspark.sql.functions import col
cols = [s for s in df.columns if "field" in s]
df.select(*(lookup_udf(col(c)).alias(c) if c in cols else c for c in df.columns)).show()
+---+------+------+------+-----+
| ID|field1|field2|field3|value|
+---+------+------+------+-----+
| a| y| y| x| 2|
| b| x| x| z| 3|
| c| z| 4| z| 3|
+---+------+------+------+-----+
Page模型有一个名为page_number的列。我使用的是Postgres。
我的问题是:假设有一位作者class Author < ActiveRecord::Base
has_many :books
end
class Book < ActiveRecord::Base
belongs_to :author
has_many :pages
end
class Page < ActiveRecord::Base
belongs_to :book
end
,如何查询作者的所有最后一页?换句话说,我想要该作者写的每本书的最后一页。我正在尝试下面的工作:
@author
修改
以下两行有效,但我希望了解更快/更清洁的解决方案:
Page.where(book_id: @author.books.pluck(:id)).select('MAX(page_number), *').group(:book_id)
答案 0 :(得分:1)
最有效的方法可能是利用postgres' window functions
这样的查询不适合activerecord常见用例,因此您可能必须使用find_by_sql
,但这可能是值得的。
在您的情况下,首先抓取图书ID可能是一个很好的电话,因为加入或额外的子查询可能不是有利的 - 您的电话。
假设您有@author.books.ids
的图书ID列表。接下来我们想要的是一个“按”分组的页面列表,这样我们就可以为每个组挑选最后一页。设1,2为相关作者的书籍ID。
我们可以使用窗口函数和postgres中的rank
函数来创建一个结果集,其中页面在书的分区(组)上排名。我们甚至会按页码对页面分区进行排序,以使最大页码(最后一页)位于每个分区的顶部。查询将如下所示:
select
*,
rank() over (
partition by book_id order by page_number desc
) as reverse_page_index
from pages
where book_id in (1,2)
我们想象的pages
结果集看起来像这样。
author 1, book 1, page 3, rank 1
author 1, book 1, page 2, rank 2
author 1, book 1, page 1, rank 3
author 1, book 2, page 6, rank 1
author 1, book 2, page 5, rank 2
author 1, book 2, page 4, rank 3
author 1, book 2, page 3, rank 4
author 1, book 2, page 2, rank 5
author 1, book 2, page 1, rank 6
页面记录按书籍分区,按页码升序排序,并在其分区中给出排名。
如果我们在之后只想要每本书的第一个排名(最后一页)进行窗口计算,我们可以像这样使用子选择:
select *
from
(
select
*,
rank() over (
partition by book_id order by page_number desc
) as reverse_page_index
from pages
where book_id in (1,2)
) as pages
where reverse_page_index = 1;
我们将上述想象结果集过滤为仅排名(reverse_page_index)为1(即最后一页)的页面记录。
现在我们的结果集将是:
author 1, book 1, page 3, rank 1
author 1, book 2, page 6, rank 1
您也可以按最后修改或任何需要订购此结果集。
在find_by_sql
中抛出该查询,您将拥有一些要使用的activerecord对象。