为什么要使用SQL构建器? Arel v.Sequel v.T-SQL

时间:2011-02-10 19:38:51

标签: ruby tsql arel sequel

我试图了解通过面向对象的构建器DSL构建SQL与参数化原始SQL字符串的好处。在研究/实现相同的查询三种方式之后,我注意到原始SQL是迄今为止最容易阅读的。这引出了一个问题,“为什么要跳过篮筐?”为什么不直接声明和使用原始SQL?

以下是我的观点:

首先,我想它会使SQL更具可移植性,因为任何具有适配器的数据库都可以使用它。我猜这是个大人物吧?但是,对大多数数据库来说,大多数T-SQL都不易理解吗?

其次,它提供了一个可以重用的查询对象 - 作为其他查询,命名范围链接等的基础。

通过构建SQL而不是声明SQL,您实现的主要投资回报是什么?

def instances_of_sql(ttype_id) #raw sql
  ttype_id = get(ttype_id).try(:id)
  ti   = get('tmdm:type-instance')
  inst = get('tmdm:instance')
  type = get('tmdm:type')

  self.class.send :sanitize_sql, [%{
    SELECT t.*
    FROM associations a
    JOIN roles type    ON type.association_id = a.id AND type.ttype_id = ?
    JOIN roles inst    ON inst.association_id = a.id AND inst.ttype_id = ?
    JOIN topics t      ON t.id = inst.topic_id
    WHERE a.topic_map_id IN (?)
    AND a.ttype_id    = ?
    AND type.topic_id = ?
  }, type.id, inst.id, self.ids, ti.id, ttype_id]
end

def instances_of_sql(ttype_id) #sequel
  ttype_id = get(ttype_id).try(:id)
  ti = get('tmdm:type-instance')
  ir = get('tmdm:instance')
  tr = get('tmdm:type')

  DB.from(:associations.as(:a)).
    join(:roles.as(:tr), :tr__association_id => :a__id, :tr__ttype_id => tr[:id]).
    join(:roles.as(:ir), :ir__association_id => :a__id, :ir__ttype_id => ir[:id]).
    join(:topics.as(:t), :t__id => :ir__topic_id).
    where(:a__topic_map_id => self.ids).
    where(:a__ttype_id => ti[:id]).
    where(:tr__topic_id => ttype_id).
    select(:t.*).sql
end

def instances_of_sql(ttype_id) #arel
  ttype_id = get(ttype_id).try(:id)
  ti   = get('tmdm:type-instance')
  inst = get('tmdm:instance')
  type = get('tmdm:type')

  #tables
  t    = Topic.arel_table
  a    = Association.arel_table
  tr   = Role.arel_table
  ir   = tr.alias

  a.
    join(tr).on(tr[:association_id].eq(a[:id]),tr[:ttype_id].eq(type[:id])).
    join(ir).on(ir[:association_id].eq(a[:id]),ir[:ttype_id].eq(inst[:id])).
    join(t).on(t[:id].eq(ir[:topic_id])).
    where(a[:topic_map_id].in(self.ids)).
    where(a[:ttype_id].eq(ti[:id])).
    where(tr[:topic_id].eq(ttype_id)).
    project('topics.*').to_sql
end

我完全赞赏命名范围,看看链接它们是如何有益的。我并不担心通过模型访问相关记录。我纯粹是在谈论构建一个复杂的查询。

2 个答案:

答案 0 :(得分:9)

@Kyle Heironimus给Nick Kallen关于Arel的想法的链接有这样一句话:

  

你会注意到派生的使用   子选项中的表格。这是   在我看来,太可怕了。只有先进   SQL程序员知道如何编写它   (我经常在工作中问这个问题   采访我从未见过   任何人都做对了)。它   不应该很难!

嗯,Kallen将这归结为SQL中的组合缺乏闭包。在某些情况下可能是这样,但我的经验更平淡 - 大多数开发人员在SQL上都很糟糕。他们只知道最基本的东西,这些基本的东西在尝试以基于集合的语言搜索程序解决方案时被误用。我不得不在我所在的一家公司争论数据库在3NF中的好处,而所有其他开发者,他们只是没有得到它。有才能的人(大多数:),但没有关于SQL或数据库的线索。

将它放在C#或Ruby或Python< insert language of choice>而开发者又开心了。他们可以坚持程序/面向对象的思维,并生成对他们来说很好的代码。

我知道这不会赢得任何选票,可能恰恰相反,但这是我的看法。 Arel看起来很有趣BTW。


作为我上面提到的评论的附录,六个多月过去了,并且在那段时间里使用了续集库,我可以说它确实是一件美丽的事情,现在我觉得我会用提前使用直接SQL。它不仅非常强大,而且允许我做简单而高级的事情,而不会有太多的搔痒(总会有一些)它可以输出它已经使用的SQL,并且它还允许我下载到SQL中,如果我觉得我需要。

这绝不会使我对大多数开发人员对SQL的理解的评论无效(我最近告诉我,一个开发人员与其他人交谈,规范化是存储空间昂贵时的遗留物。哦,亲爱的!)只是那些真正了解数据库的人显然已经完成了续集库的开发。如果您了解SQL和db设计等,那么它可以更快地为您提供更多功能。我不能说我用过的其他ORM也是如此,但也许其他人会有不同的想法。

答案 1 :(得分:4)

你已经了解了很多原因。

Here是来自Arel创作者的想法。