2012-07-16 122 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