为什么SQLite3中的LIKE在这个语句中工作但是=不?

时间:2012-04-10 00:13:51

标签: ruby sqlite md5

我使用SQLite3并有一个名为blobs的表,用于存储内容和* hash_value *。

这是架构:

CREATE TABLE "blobs" (
  "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
  "content" blob,
  "hash_value" text,
  "created_at" datetime NOT NULL,
  "updated_at" datetime NOT NULL
);

现在我插入了一些数据。看起来像这样:

1|--- foo
...
|34dc86f45b3dc92b352fd45f525192c0|2012-04-09 17:02:54.219504|2012-04-09 17:02:54.219504

我尝试了以下两个问题:

  • select * from blobs where hash_value = '34dc86f45b3dc92b352fd45f525192c0';
  • select * from blobs where hash_value LIKE '34dc86f45b3dc92b352fd45f525192c0';

第一个不起作用,但第二个起作用。我不明白为什么=运算符不起作用。

我试图将其分解为一个简单的示例,其中我的哈希只是'abc'并且=有效。我的意思是这个字符串不会太长。

修改

好的,我实际上把它缩小到了这个:

  • 我使用Ruby来生成像Digest::MD5.hexdigest("foobar")
  • 这样的哈希
  • 这会生成如下字符串:'3858f62230ac3c915f300c664312c63f'
  • 我的测试看起来有点像这样:b = Blob.new(...);b.save!;Blob.find_by_hash(b.hash)
  • 并且find_hash为Blob.find(:all, :conditions => ["hash_value = ?", hash_value])
  • 如果我手动将哈希值设置为'3858f62230ac3c915f300c664312c63f'(硬编码字符串),则可以正常工作。
  • 但如果生成此字符串,则会出现以下错误:

    Failure/Error: Blob.find_by_hash(b.hash_value)[0].load.should == txt
     ArgumentError: wrong number of arguments (0 for 1)
    

我无法像上面所述查询SQLite3。

解决方案

解决方案是:

  • 使用Digest :: MD5.base64digest(“foobar”)而不是使用Digest :: MD5.hexdigest(“foobar”)

我不知道为什么sqlite3存在hexdigest的问题,但最终确实存在一些问题。

2 个答案:

答案 0 :(得分:2)

两者之间的差异是编码:

Digest::MD5.hexdigest("foobar").encoding #=>  #<Encoding:ASCII-8BIT> 
Digest::MD5.base64digest("foobar").encoding #=> #<Encoding:US-ASCII> 

我认为hexdigest有一个特殊的原因,就是为什么hexdigest有8位编码(这实际上意味着'这是原始数据',但这正是ruby似乎所做的。当ruby sqlite3驱动程序看到ascii-8bit编码时它将值作为blob而不是文本绑定到查询。这反过来会影响sqlite3进行比较的方式(虽然我不明白如何)。

另见this question

答案 1 :(得分:0)

解决方案是:

使用Digest :: MD5.base64digest(“foobar”)而不是使用Digest :: MD5.hexdigest(“foobar”)。 我不知道为什么sqlite3有hexdigest的问题,但确实有一些可疑的事情。