如何将变量传递给Ruby中的预处理语句?

时间:2015-04-24 20:17:19

标签: ruby sqlite prepared-statement

我在Ruby中有一个查询数据库并打印出一些数据的方法,而我正在尝试使用预备语句。

这是没有准备好的声明的正常运作方法:

def print_state_speakers(*states)
  puts "STATE SPEAKERS"
  state_string = "'#{states.*"', '"}'"
  state_speakers = $db.execute("
    SELECT name, location 
    FROM congress_members 
    WHERE location IN (#{state_string})
    ORDER BY location")
  state_speakers.each { |rep, location| puts "#{rep} - #{location}" }
end

这是我尝试使用预准备语句的相同方法:

def print_state_speakers(*states)
  puts "STATE SPEAKERS"
  state_string = "'#{states.*"', '"}'"
  begin
    pst = $db.prepare "SELECT name, location 
    FROM congress_members 
    WHERE location IN (?)
    ORDER BY location"
    state_speakers = pst.execute state_string
  end
  state_speakers.each { |rep, location| puts "#{rep} - #{location}" }
end

这是我调用方法的地方:

 print_state_speakers('NJ', 'NY' , 'ME', 'FL', 'AK')

当我用第一种方法运行文件时它会显示数据,当我使用第二种方法时,它什么也没显示。它不会引发错误。我觉得语法需要与传入的字符串不同,但我一直在网上搜索并乱用它一段时间而无法让它工作。任何有关如何修复准备好的声明的见解将不胜感激。

1 个答案:

答案 0 :(得分:0)

当你这样说时:

pst = $db.prepare "SELECT name, location 
FROM congress_members 
WHERE location IN (?)
ORDER BY location"
state_speakers = pst.execute state_string

pst.execute调用将转义并引用state_string,就像任何其他字符串一样。但是你的state_string实际上不是一个单独的字符串,它是一个表示为(Ruby)字符串的SQL列表,因此你最终会双重引用所有内容。

一个简单的解决方案是使用字符串插值来添加适当数量的占位符,然后让SQLite3::Statement处理所有引用本身:

placeholders = ([ '?' ] * states.length).join(',')
pst = $db.prepare "SELECT name, location 
FROM congress_members 
WHERE location IN (#{placeholders})
ORDER BY location"
state_speakers = pst.execute states

这种字符串插值的使用非常安全,因为您确切知道placeholders中的内容。