2012-07-16 120 views
2

我正在使用find_by_sql来执行SQL查询。 我希望能够使用Soundex和Levenshtein,但为了使用Levenshtein,我需要将函数作为一个文件加入。如何包含自定义SQL函数

这是我到目前为止的代码:

info = params[:email].split('@') 
name = info[0] 
domain = info[1] 

levenshtein = File.open("./lib/assets/mysql-function-levenshtein.sql") 

results = Domain.find_by_sql(
    "" + levenshtein + " 
    SELECT * 
    FROM domains 
    WHERE domain = '" + domain + "'" 
) 

我不知道,如果简单地把它放置在查询甚至有效。

什么是最好的实现?

通过我想包括文件的方式是这样的: https://github.com/vyper/levenshtein-sql

+0

您是否尝试运行?我可能会使用'File.read'而不是'File.open',或者将'find_by_sql'调用包装在'File.open do ... end'块中。否则我不太喜欢使用自定义SQL查询。难道你不能只是在数据库中定义函数,并做一个'where(“levensthtein('leonardo','leonardu')”)'?每次运行查询时都没有必要定义函数,对吗? – Frost 2012-07-16 08:42:04

+0

是的,'File.read'是一个使用的。 – 2012-07-16 08:55:46

+0

我将如何去定义数据库上的函数? – 2012-07-16 08:56:14

回答

5

首先,我想你会更好,只是限定了与迁移的数据库功能,让你止跌”吨有重新定义它的每个查询要使用它:

class AddLevenShteinFunctionToDatabase < ActiveRecord::Migration 
  def up 
    levenshtein = File.read("/path/to/levenshtein.sql") 
    execute levenshtein 
  end 

    def down 
    # maybe put some code here to delete the function 
    end 
end 

有了这个做,你还可以添加一个范围,你Domain模型做这些类型的查询:

scope :levenshtein, lambda {|s1, s2| select("levenshein(#{s1}, #{s2})") } 

有了这个,你应该能够编写查询是这样的:

results = Domain.levenshtein("LEONARDO", "LEONARDU").where(:domain => domain) 
+0

感谢您的回答,但是我担心使用Active Record会对性能产生影响。每秒会有很多请求,而且我被告知执行原始SQL将证明速度更快。 – 2012-07-16 09:27:40

+0

在这种情况下,我建议您编写一个基准测试来检查是否确实如此,如果是这样,只需使用'Domain.find_by_sql(“select levenshtein('#{s1}','#{s2} ')from domain where'domain ='#{domain}')' – Frost 2012-07-16 09:44:51

+0

谢谢,我可以在'find_by_sql'中使用这个存储函数吗? – 2012-07-16 10:06:36