我正在尝试构建一个“拉出一些数据并显示它”的应用程序。为了提取数据,我们有大量特定于站点的oracle sql(存储过程,奇怪的表达式和诸如此类的东西)。
我需要做的一件事就是创建oracle视图,然后在这些视图中指向activerecord。但我宁愿将所有SQL放在一个地方 - 红宝石应用程序本身 - 而不是在oracle和ruby中。我想在原始SQL select子句上创建一个活动的记录对象,然后能够使用所有常用的activerecord内容。
现在 - 我知道Oracle SQL支持这一点。我们来看看:
select n.name_id, name, munge(n.name) as munged from name
通常你会创建一个视图munged_name,一个类MungedName,其结果是
MungedName.like(:name , 'Foo%')
会(最终)生成如下所示的SQL:
select T1.name_id, T1.name, T1.munged
from munged_name as T1
where T1.name like 'Foo%'
但是,我想要做的是让ActiveRecord使用sql select作为FROM子句中的子查询:
select T1.name_id, T1.name, T1.munged
from (select n.name_id, name, munge(n.name) as munged from name) as T1
where T1.name like 'Foo%'
直接把它塞进那里 - Oracle会完美地优化它。这样,我的员工想要做的所有奇怪的查询都在一个位置 - 在模型类定义中。
ActiveRecord会这样做吗?我会继续寻找 - 看看我能在我得到答案之前找到答案:)。
答案 0 :(得分:0)
我怀疑传递该SQL片段应该有效。
MungedName.from("select n.name_id, name, munge(n.name) as munged from name").like(:name , 'Foo%')
但是你可能正在寻找更像Ruby的东西,所以你当然可以在Arel中生成from
片段:
sql = Name.select([:name_id, :name, "munge(name)"]).to_sql
MungedName.from(sql).like(:name , 'Foo%')
我没有从命令行尝试任何此类操作。我怀疑我输入的内容会干净利落,但这个想法基本相同。 Arel可用于生成复杂的SQL,并将该SQL提供给另一个Arel查询。
我不确定from
部分,但我怀疑它会按预期工作。如果您查看方法来源:
http://www.ruby-doc.org/gems/docs/a/arel-3.0.2/Arel/SelectManager.html#method-i-from
def from table
table = Nodes::SqlLiteral.new(table) if String === table
...
end
SqlLiteral
类只是一种绕过任何引用或其他方式的方法。
答案 1 :(得分:0)
查看代码 - 它不起作用。没有self.from =方法。当您在table_name中阻塞原始sql时,它会引用它并将其视为表名。这是公平的。 activerecord ruby在其中一直有'quoted_table_name'。
然而,对于association.rb:
有一个有趣的评论# == Table Aliasing
#
# Active Record uses table aliasing in the case that a table is referenced multiple times
# in a join. If a table is referenced only once, the standard table name is used. The
# second time, the table is aliased as <tt>#{reflection_name}_#{parent_table_name}</tt>.
# Indexes are appended for any more successive uses of the table name.
如果可以说服activerecord始终为MungedName模型设置别名(即使没有连接),并使用一些不带引号的东西作为from的内容, 可能有效。不过,我不得不破解图书馆。