我有一些复杂的SQL查询需要转换为漂亮而干净的AR代码,而且我遇到了一些麻烦。
以下是查询:
SELECT a.*
FROM
fixed_assets a
INNER JOIN
(
SELECT e.id, e.fixed_asset_id
FROM
fixed_asset_book_entries e
WHERE e.book_id = %SOME_VALUE_1%
) e_mod
ON e_mod.fixed_asset_id = a.id
INNER JOIN
(
SELECT s.fixed_asset_book_entry_id,
s.status,
ROW_NUMBER() OVER (PARTITION BY s.fixed_asset_book_entry_id ORDER BY s.created_at DESC) AS rn
FROM
status_changes s
WHERE s.created_at < %SOME_VALUE_2%
) s_mod
ON s_mod.fixed_asset_book_entry_id = e_mod.id AND s_mod.rn = 1 AND s_mod.status <> 'inactive'
ORDER BY a.id;
所以,重点是提取这些fixed_assets
行,这些行与某些fixed_asset_book_entries
相关book_id
,并且在特定日期之前有status_change
行状态除inactive
。
我想要最终得到的是类级别(范围?)方法FixedAsset.active_within_book_on_date(book_id, date)
,它将返回FixedAsset对象,符合我上面解释的限制。我熟悉joins
方法,但除了将原始SQL传递给row_number
之外,我不知道如何处理joins
函数。
答案 0 :(得分:1)
我认为你能做的最好就是以下几点。在lib/sql_template.rb
:
class SqlTemplate
attr_reader :sql
# Load the file and process the ERB
# Call it like this:
# sql = SqlTemplate.new(filename, binding)
def initialize(filename, the_binding)
raw_code = File.read(File.join(Rails.root, 'lib/sql', filename))
template = ERB.new(raw_code)
@sql = template.result(the_binding)
end
end
然后在lib/sql/active_within_book_on_date.sql
中定义原始SQL。那将允许你这样做:
class FixedAsset
def self.active_within_book_on_date(book_id, date)
template = SqlTemplate.new('active_within_book_on_date.sql', binding)
self.find_by_sql(template.sql)
end
end
您的SQL文件如下所示:
SELECT a.*
FROM
fixed_assets a
INNER JOIN
(
SELECT e.id, e.fixed_asset_id
FROM
fixed_asset_book_entries e
WHERE e.book_id = <%=book_id%>
) e_mod
ON e_mod.fixed_asset_id = a.id
INNER JOIN
(
SELECT s.fixed_asset_book_entry_id,
s.status,
ROW_NUMBER() OVER (PARTITION BY s.fixed_asset_book_entry_id ORDER BY s.created_at DESC) AS rn
FROM
status_changes s
WHERE s.created_at < '<%=date%>'
) s_mod
ON s_mod.fixed_asset_book_entry_id = e_mod.id AND s_mod.rn = 1 AND s_mod.status <> 'inactive'
ORDER BY a.id;
这可能就像你能得到的那样'干净整洁'。