如何将Ruby函数放入SQLite3查询中?

时间:2012-12-18 18:54:36

标签: ruby-on-rails ruby methods sqlite

我有一个函数需要放入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中找到name的值,其中name列的值与用户输入之间的编辑距离小于3。问题是我不知道如何在查询中使用Ruby函数。这甚至可能吗?

2 个答案:

答案 0 :(得分:2)

查看create_function method。您可以使用它来创建这样的自定义函数(您已经定义了levenshtein Ruby方法):

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连接都定义了函数 - 如果你在控制器中添加函数它似乎有效,但这并不理想。)

已经展示了可以的完成方式,我不确定是否应该在网络应用中完成。您可能不希望在生产中使用Sqlite。也许如果您使用例如它可能会有用Postgres在生产中有自己的levenshtein函数(如the Tin Man’s answer中所述),但想在开发中使用Sqlite。

答案 1 :(得分:0)

如果需要检索列的值以将其插入Ruby函数,则必须首先检索该值。

DBM无法在运行的代码中调用您的方法;您必须拥有该值,将其传递给您的方法,然后在二级查询中使用该结果。

或者使用内置Levenshtein function的DBM,如PostgreSQL,或者在纯SQL中定义它。