sqlite3 varchar与“like”匹配但不是“=”

时间:2011-09-15 22:02:43

标签: sqlite ruby-on-rails-3.1

使用Rails 3.1和sqlite3进行开发,测试环境。

在迁移中添加了一个新表:

create_table :api_keys do |t|
  t.string :api_key
  t.integer :user_id
  t.timestamps
end

这将生成一个包含以下模式的表:

create_table "api_keys", :force => true do |t|
  t.string   "api_key"
  t.integer  "user_id"
  t.datetime "created_at"
  t.datetime "updated_at"
end

在ActiveRecord模型中:

before_create :fill_api_key

private

def fill_api_key
  self.api_key = SecureRandom.hex(30)
end

ActiveRecord的动态查找程序方法find_by_api_key(api_key)不起作用(返回nil)。与:相同:

ApiKey.where({:api_key => 'something'}).first

在sqlite3中,我执行以下操作:

insert into api_keys (id, api_key) values (-1, '12345');

如果我现在运行一个选择:

select api_keys.* from api_keys where api_keys.api_key = '12345';

将找到记录。

如果我运行未经过滤的选择,则会显示从我的应用程序创建的预先存在的数据:

select api_keys.* from api_keys;

如果我尝试通过将一个已存在的记录中的长十六进制字符串粘贴到我的查询中来查找预先存在的记录:

select api_keys.* from api_keys where api_keys.api_key = 'long hex string';

然后它不返回任何结果。如果我试着这样做:

select api_keys.* from api_keys where api_keys.api_key like 'long hex string';

然后我得到一场比赛。

我在api_keys.api_key上创建了一个索引,但没有效果。

此问题会影响我的应用程序中的另一个模型,该模型使用Digest :: SHA1 :: hexdigest生成类似的随机十六进制数字字符串。

詹姆斯

2 个答案:

答案 0 :(得分:8)

好吧,我想我已经明白了。问题不在于这是Rails 3.1,而是你可能已经从Ruby 1.8.7转移到了Ruby 1.9.2。

在Ruby 1.9中,所有字符串现在都已编码。默认情况下,所有字符串都应为UTF-8,但SecureRandom.hex(30)会返回ASCII-8BIT的编码。

您可以使用以下命令在sqlite3中确认:.dump api_keys,您可能会看到api_key字段如下所示:

INSERT INTO "api_keys" VALUES(1,X'376433356530[...]',1);    
INSERT INTO "api_keys" VALUES(1,'1234567890[...]',1);

第一个是SecureRandom生成的api_key。第二个是通过键入控制台创建的。 X表示字段编码为blob,而不是字符串。

要解决此问题,请将fill_api_key更改为:

self.api_key = SecureRandom.hex(30).force_encoding('UTF-8')

我刚才有点 大时间 ,所以希望它可以帮助你。

这里有关于1.9中字符串更改的一些很好的细节:http://blog.grayproductions.net/articles/ruby_19s_string

答案 1 :(得分:0)

如果您使用的是十六进制数字字符串,如果您想使用其中x = y select,则必须具有大小写匹配。与某些数据库不同,SQLite区分大小写。