2012-12-18 39 views
0

我有一個需要放入SQLite3查詢的函數。如何將Ruby函數放入SQLite3查詢中?

我有以下方法:

def levenshtein(a, b) 
    case 
    when a.empty? then b.length 
    when b.empty? then a.length 
    else [(a[0] == b[0] ? 0 : 1) + levenshtein(a[1..-1], b[1..-1]), 
     1 + levenshtein(a[1..-1], b), 
     1 + levenshtein(a, b[1..-1])].min 
    end 
end 

,我想要做一個查詢,看起來像這樣:

@results = The_db.where('levenshtein("name", ?) < 3', '#{userinput}') 

我想找到The_db其中名稱的值是什麼編輯名稱列的值與用戶輸入之間的距離小於3。問題是我不知道如何在查詢中使用Ruby函數。這甚至有可能嗎?

回答

2

看看create_function method。您可以使用它來創建這樣的自定義函數(如您已定義了levenshtein紅寶石法):

db.create_function "levenshtein", 2 do |func, a, b| 
    func.result = levenshtein(a, b) 
end 

然後,您可以用它在你的SQL:

# first set up some data 
db.execute 'create table names (name varchar(30))' 
%w{Sam Ian Matt John Albert}.each do |n| 
    db.execute 'insert into names values (?)', n 
end 

#Then use the custom function 
puts db.execute('select * from names where levenshtein(name, ?) < 3', 'Jan') 

在這個例子中,輸出是

Sam 
Ian 
John 

我沒有在Rails中測試過,但我認爲它應該工作,查詢字符串只是傳遞到數據庫。您可以使用ActiveRecord::Base.connection.raw_connection獲取Sqlite db對象。 (我不知道如何配置Rails,以便所有ActiveRecord連接都具有定義的功能 - 如果您在控制器中添加該功能,似乎工作正常,但這並不理想)。

已經展示瞭如何這種可以做,我不知道這是否可以在Web應用程序來完成。你可能不想在生產中使用Sqlite。如果你正在使用例如Postgres在生產中具有自己的levenshtein函數(如the Tin Man’s answer中所建議的),但希望在開發中使用Sqlite。

+0

我試過了,但頁面從未加載......它只是卡住了...... – areke

+0

其實,這是因爲levenshtein函數耗時太長......這意味着你回答了我的問題。謝謝!如果您知道另一種方法來測試兩個字符串之間的相似性,請告訴我:D – areke

+0

使用與生產中不同的DBM進行開發是正常的,但不是真正的建議,因爲SQL實現中可能存在差異,會泄漏回代碼中;我們編寫代碼來容納數據庫,然後在針對不同的DBM推送生產後導致出現問題。考慮到PostgreSQL是免費的,幾乎適用於開發人員可以使用的任何機器,所以在開發過程中很難證明不使用它。是的,設置它有一點點花費,但一旦完成,它就非常透明。 –

0

如果您需要檢索列的值以將其插入到Ruby函數中,那麼您必須先檢索該值。

DBM無法在您的運行代碼中調用您的方法;您必須具有該值,將其傳遞給您的方法,然後在輔助查詢中使用結果。

或者使用內置的Levenshtein function的DBM,如PostgreSQL或使用純SQL進行定義。

+0

你能舉個例子嗎? – areke

+0

我想你可以把那一部分弄清楚。做一個選擇從正確的記錄中獲取所需的字段,計算距離,然後進行下一次搜索。 –

+0

這是否意味着我必須迭代名稱列中的所有值? – areke

相關問題