为什么我使用 like '%text%' 获取结果查询实际上在另一列中的数据的列

Reason why am I getting results querying a column with Data actually in another column, using like '%text%'

使用 Firebird 2.5.8 和带有十几个 blob 字段的 table,我有这种奇怪的查询行为:

SELECT * 
FROM TABLE 
WHERE BLOBFIELD4 LIKE '%SOMETEXT%' 

虽然 SOMETEXT 实际上在不同的列中而不是在 BLOBFIELD4 中(每个 blob 列都会出现),但我得到了结果。

我错过了什么?

感谢提供数据。我使用最新的 IB ExpertFirebird 2.5.5(我手头的东西)进行了一些快速测试。

看来您实际拥有的数据比您想象的要多得多。

首先 - 将文本数据保存在标记为 CHARSET NONE 的列中是一种糟糕且危险的做法!确保您的列标有一些合理的字符集,例如 Windows 1250 或 UTF8 或其他。而且您的所有应用程序(包括开发工具)与数据库服务器的连接也有一些明确定义的适合您的文本数据的字符集。
https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/
或者,如果您希望这些 BLOB 被视为二进制 - 然后明确地将它们创建为 SUB_TYPE BINARY 而不是 SUB_TYPE TEXT

但是,这里是 运行 到您的数据库的简单脚本。

alter table comm
add    NF_VC    VARCHAR(4000) CHARACTER SET UTF8,
add    NF_BL    BLOB SUB_TYPE 1 SEGMENT SIZE 4096 CHARACTER SET UTF8

然后

update comm
set nf_vc = '**' || com1 || '**'

然后

update comm
set nf_bl = '@@' || nf_vc || '@@'

注意,我故意强制 Firebird 进行转换 BLOB -> VARCHAR -> BLOB。 保险起见。

现在检查一些数据。

 select id_comm, nf_vc
 from comm where
 nf_vc containing 'f4le dans 2 ans'

 select id_comm, nf_bl
 from comm where
 nf_bl containing 'f4le dans 2 ans'

你现在看到了什么?

在第一张图片上我们看到了非常神秘的东西——线被选中了,但是我们在里面看不到你的搜索模式,"f4le dans 2 ans"。 但 !!! 你能看到标记、双星号和 ** 吗? 是的,你可以,一开始!但是你看不到他们的结局!!! 这意味着,您不会看到整个文本,而只会看到它的第一部分!

在第二张图片上 - 您看到完全相同的行 ID=854392,但重新转换回 BLOB 并在两端另外标记了 @@

你能看到开始和结束的标记吗?
你能看到你的搜索模式吗?

是的,是的 - 如果您查看网格行(白色)。
不,不 - 如果您查看工具提示(黄色)。

因此,您搜索的数据再次出现 - 它确实存在。但是你就是因为某些原因没看到它。

现在,什么时候可能是字符串未完全显示的典型原因? 它可以是零值字节(或几个字节,UNICODE 代码点),C 语言标记行结束的方式,Windows 和许多库和程序中广泛使用的习惯。或者可能是其他一些不寻常的值(EOF、EOT、-1 等),这会使您使用的那些程序错误地检测到文本的结尾,而实际上它还没有结束。

再看看这两张截图,哪里的线条开始不一样了?它在 \viewkind4 ... \par} 之后和 pard 之前。注意奇怪的异常!那说 pard 应该以反斜杠开头 - \ - 是一个有效的 RTF 命令。但它前面是一些不可见的东西,一些空白的东西。它可以是什么?...

让我们回到您评论中的原始查询。

此外,将重要细节放在评论中是不好的做法!他们很难在那里找到任何人,因为他们从一开始就没有追踪故事。添加的评论越多,就越难。对你来说正确的途径是编辑问题,将新数据添加到问题正文中,然后添加评论(为了通知起见)说问题已被编辑。以后请以这种方式添加新数据。

select id_comm, COM1
from comm where
COM1 containing 'f4le dans 2 ans'

乍一看,我们的钓鱼一无所获,我们看到的文字没有您的模式,以 \par} 结尾。

但真的是这样吗?切换到二进制视图,然后....

瞧! found-lost-found-again pard 之前有什么?我之前谈到过 ZERO BYTE

那么,到底发生了什么,总结一下。

  1. Firebird 是正确的,找到了数据,因为数据确实存在于 BLOB 中。
  2. 您的应用程序读取数据不正确。与零字节混淆,它们只显示部分数据,而不是全部数据。
  3. 您的应用程序正在写入数据,可能不正确。或者数据本身。

那个零字节是怎么结束的?为什么 RTF 结构损坏,在 pard 之前缺少反斜线?插入数据时传递给服务器的数据大小是否大于应有的大小,在有意义的数据之后传递了一些垃圾?数据大小是否正确,但数据内容在插入前已损坏?

那里有点可疑。我不认为 RTF 规范明确禁止零字节,但它是非常不典型的,因为它会在太多应用程序和库中触发这样的错误。

P.S。 table 有许多 BLOB 类型的列的设计似乎很差。 "wide" table经常会导致以后的开发和维护出现问题。 虽然这不是你的问题的本质,但请考虑将这个 table 重新制作成一个窄的,并将你的数据保存为多个单 BLOB 行。 它现在会给你一些固定的附加工作,但可能会让你在未来避免滚雪球般的问题。