sql - 为什么我在另一列中使用“%text%”之类的数据查询列的结果的原因
问题描述
使用 Firebird 2.5.8 和一个包含十几个 blob 字段的表,我有这种奇怪的行为以这种方式查询:
SELECT *
FROM TABLE
WHERE BLOBFIELD4 LIKE '%SOMETEXT%'
虽然我得到的结果SOMETEXT
实际上是在不同的列中而不是在BLOBFIELD4
(每个 blob 列都发生)。
我错过了什么?
解决方案
谢谢你的数据。我使用最新的IB Expert和Firebird 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}
。
但真的是这样吗?切换到二进制视图,然后....
瞧!在发现-失去-再次发现之前有什么pard
?我之前谈到的就是零字节。
所以,到底发生了什么,总结一下。
- Firebird 是正确的,找到数据是因为数据确实存在,在 BLOB 中。
- 您读取数据的应用程序不正确。与零字节混淆,它们只显示部分数据,而不是全部数据。
- 您的应用程序(写入数据)可能不正确。或者数据本身。
那个零字节是如何在那里结束的?为什么 RTF 结构损坏,之前缺少反斜杠pard
?插入数据时传递给服务器的数据大小是否大于应有的大小,在有意义的数据之后传递了一些垃圾?数据大小是否正确,但插入前数据内容已损坏?
那里有些可疑。我不认为 RTF 规范明确禁止零字节,但拥有它是非常不典型的,因为它会在太多的应用程序和库中触发这样的错误。
PS 具有许多具有 BLOB 类型的列的表的设计似乎很差。“宽”表往往会导致以后的开发和维护出现问题。虽然这不是您问题的本质,但请考虑将这张表重新制作成一个窄表,并将您的数据保存为多个单 BLOB 行。它现在会给你一些固定的附加工作,但将来可能会让你免于滚雪球的问题。
推荐阅读
- c++ - 分发原始 msvcp.dll 或安装 vc_redist.exe
- scala - 是什么导致匹配元组列表的模式保护中出现这种类型错误
- go - 为什么 `fmt.Println("%T\n", e)` 其中 `e` 是一个错误变量会打印出来
而不是它的类型? - google-cloud-platform - 通过 API 管理 GCP 配额
- sql-server - 准备好的语句中的所有参数都应该使用占位符吗?
- python - 切片将 UserList 转换为列表
- webgl - 在 WebGL 中,可以使用片段着色器来设置 LUMINANCE 纹理吗?
- c# - SSL 端口 5671 上的 RabbitMQ 无法访问,但可在 telnet 上访问
- .net - 打开或操作 Jpeg2000 压缩的 Tiff
- gradle - Kotlin 1.3.20 与 Gradle 5.1.1 compileKotlin2Js 执行热重载