从Ruby on Rails调用PL/pgSQL存储过程

7
我正在一个PostgreSQL环境下担任数据库设计师/管理员的项目中工作。领导决定使用Rails进行应用逻辑,并招募了一名Rails程序员。
Rails程序员表示,他通常编写所有的应用代码,不喜欢由别人传递存储过程所带来的缺乏控制感觉,并且他从未在rails中做过这件事。
由于数据库使用了很多继承/EERM,因此存储过程和触发器将使他的工作变得更加轻松,并且使用存储过程还可以获得性能上的好处。
我的四个问题如下:
1) 如何从Rails中调用没有返回值的pl/pgSQL存储过程
2) 如何从Rails中调用具有单个返回值(1行/1列)的pl/pgSQL存储过程
3) 如何从Rails中调用具有1行多列返回值的pl/pgSQL存储过程
4) 如何使用OUT参数从Rails中调用pl/pgSQL存储过程?
谢谢!

6
除非你能说服你的Rails程序员使用类似Sequel的东西,否则你会度过难熬的时光。默认的Rails ORM(ActiveRecord)不相信数据库应该包含任何逻辑,并且不理解比select *和简单的连接更复杂的内容。如果你违反惯例,使用“高级”的东西如触发器、存储过程或者甚至是预编译语句,那么你将一直与它斗争。 - mu is too short
2
是的...基于过程和继承的数据库+ActiveRecord会直接导致进入http://thedailywtf.com/领域。你必须接受选择使用Rails(以及可能的ActiveRecord ORM)并放弃你的数据库设计,然后创建一个遵循ActiveRecord约定的数据库(没有像"外键"或"约束"这样愚蠢的东西,谁需要它们呢?)。或者,改变决策,看看是否可以像Mu指出的那样让他们至少使用一个理智的ORM。 - Craig Ringer
1个回答

9

你好,我正在使用这段代码与PgSQL存储过程一起工作。这段代码涵盖了除最后一个问题之外的所有内容。

   class SpActiveRecord < ActiveRecord::Base

      self.abstract_class = true
      #without return value
      def self.execute_sp(sql, *bindings)
        perform_sp(:execute, sql, *bindings)
      end
      #select many return values
      def self.fetch_sp(sql, *bindings)
        perform_sp(:select_all, sql, *bindings)
      end
      #select single return value
      def self.fetch_sp_val(sql, *bindings)
        perform_sp(:select_value, sql, *bindings)
      end

      protected
      def self.perform_sp(method, sql, *bindings)
        if bindings.any?
          sql = self.send(:sanitize_sql_array, bindings.unshift(sql))
        end
        self.connection.send(method, sql)
      end

    end

例子

class Invoice < SpActiveRecord

 def create_or_update
       raise ReadOnlyRecord if readonly? or !new_record?

        self.id = fetch_sp_val("SELECT * FROM billing.invoice_generate(?,?,?)", 
                               self.account_id,
                               self.start_date,
                               self.end_date)

       @new_record = false
       true
   end
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接