2012-11-19 54 views
1

我有一個例子字符串「佳能的PowerShot 12.1萬像素」,當我運行下面的代碼,它似乎失敗:插入Ruby的字符串到sqlite的

db.execute "CREATE TABLE IF NOT EXISTS Products(id INTEGER PRIMARY KEY, stockID INTEGER, Name TEXT)" 

id = 12345 
name = "Canon PowerShot 12.1-Megapixel"  

db.execute("INSERT INTO Products (stockID, Name) VALUES (#{id}, #{name})") 

錯誤代碼是:

C:/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/sqlite3-1.3.6-x86-mingw32/lib/sqlite3/d 
atabase.rb:91:in `initialize': near "PowerShot": syntax error 
(SQLite3::SQLExcep tion) 
     from C:/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/sqlite3-1.3.6-x86-mingw32/ 
lib/sqlite3/database.rb:91:in `new' 
     from C:/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/sqlite3-1.3.6-x86-mingw32/ 
lib/sqlite3/database.rb:91:in `prepare' 
     from C:/Ruby/Ruby193/lib/ruby/gems/1.9.1/gems/sqlite3-1.3.6-x86-mingw32/ 
lib/sqlite3/database.rb:134:in `execute' 
     from E:/Documents/Cowboom/scraping/DBDOTDList.rb:48:in `<main>' 

任何想法爲什麼這後「PowerShot」死亡?

回答

9

您正在創建的字符串周圍沒有引號。所以字符串實際上是:

"INSERT INTO Products (stockID, Name) VALUES (12345, Canon PowerShot 12.1-Megapixel)" 

正如你所看到的,這是無效的SQL;它會嘗試將Canon PowerSho 12.1-Megapixel解釋爲SQL語句的一部分,而不是字符串。

你可以嘗試把周圍的變量插值引號來解決這個問題:

db.execute("INSERT INTO Products (stockID, Name) VALUES (#{id}, '#{name}')") 

然而,這是一般一個壞主意。如果字符串包含',那麼這將結束SQL語句中的字符串,導致錯誤(或者更糟糕的是,如果攻擊者這樣做,則使用SQL injection漏洞;請參閱this comic for an amusing example)。通常應避免嘗試通過插入或附加字符串來構建SQL查詢;你可能會認爲你可以過濾掉或引用錯誤的字符,但這實際上很難做到。

相反,你應該使用綁定的參數要傳遞到您的SQL語句中的任何變量數據:

db.execute("INSERT INTO Products (stockID, Name) VALUES (?, ?)", [id, name]) 

的更多信息和示例見sqlite3-ruby documentation

+0

哇,謝謝你的好解釋。經過一些更多的搜索後,我實際上找到了你提供的完全相同的例子,但是直到你解釋它之前,我都不知道爲什麼。感謝:D – rlhh