【问题标题】:Updating Firebird BLOB field appending text更新 Firebird BLOB 字段附加文本
【发布时间】:2019-07-29 13:03:33
【问题描述】:

问题

当此值为 NULL 时,无法使用简单的 concat (||) 将文本附加到 blob 字段。

文档库:https://firebirdsql.org/refdocs/langrefupd21-blob.html

测试环境

假设类型:

  • fieldTarget ~ BLOB
  • tablePk ~ VARCHAR(5)

像这样:

UPDATE tablename
SET fieldTarget = fieldTarget || :string
WHERE tablePk = :pkTarget;

执行后,没有返回任何错误,但该字段仍然null

【问题讨论】:

  • 您确定您实际上使用的是 Firebird 2.1,它是方言 3 数据库吗? fieldTarget 的完整类型是什么?发生什么了?你有错误吗?您使用什么语言和驱动程序?也许问题是:string 也被键入为 blob,而您的驱动程序没有正确处理这个问题?
  • 不知何故我反复阅读了“当这个值为NULL时”...对null的任何操作都会产生null。

标签: firebird firebird2.1


【解决方案1】:

所有字符串操作(如 ||-concatenation)都受到最大 VarChar 大小限制(即 32 KB,小于 UTF-8 编码文本中的 8200 个字母)的约束。

但似乎有面向BLOB 的函数。它也不需要用COALESCE 转义NULL-values。

LIST 返回一个字符串,该字符串由组中的非 NULL 参数值组成,由逗号或用户提供的分隔符分隔

https://firebirdsql.org/refdocs/langrefupd21-aggrfunc-list.html

因此,使用derived tables

Select LIST(ALL X, '') From
 ( Select fieldTarget as x From tablename Where tablePk = :pkTarget
      UNION ALL
   Select Cast( :string AS VarChar(8191) ) From RDB$DATABASE ) 
As TMP

类型转换是将数据类型分配给仅参数表达式。

附:该文件还声称

列表值的顺序未定义。

P.P.S.准备运行示例,在 FB 2.1.7 上测试

Select LIST(ALL X, '') From
 ( Select Cast( :str_pre AS VarChar(8191) ) as X From RDB$DATABASE
      UNION ALL
   Select /* DATA column */ RDB$TRIGGER_SOURCE
          From /* DATA table */ RDB$TRIGGERS
          Where /* PK ID */ RDB$TRIGGER_NAME  = :pkTarget
      UNION ALL
   Select Cast( :str_post AS VarChar(8191) ) From RDB$DATABASE
)

传递像RDB$TRIGGER_1 这样的名称会给你一个没有源文本的system trigger,因此在该字段中有一个NULL 值。很容易检查你不需要COALESCE-screening 这里:-D

【讨论】:

  • 由于 Firebird 2.1,连接 (||) 支持(文本)blob,应该不需要魔法。见firebirdsql.org/refdocs/langrefupd25-concat.html
  • @MarkRotteveel 但有两个限制:不会跳过 NULL 值,但会导致 NULL 结果,并且只有小的 VARCHAR 大小的 BLOB 可以使用它(IOW 不是将运算符扩展到 BLOB,而是隐式类型转换BLOB 到 VARCHAR)。请参阅firebirdsql.org/file/documentation/release_notes/html/… "(v.2.1) 在各种评估级别,引擎现在将 32,765 字节字符串大小限制内的文本 BLOB 视为 VARCHAR。现在允许文本 BLOB 表现得像字符串的操作是:赋值、转换和连接(|| 运算符)"
  • 嗯,这是在摘要/目录中明确说明的:““短”BLOB 可以伪装成长 VARCHAR”:-D // 哦,第三个限制:只有 sub_type-text BLOB 是这样,不是默认的“二进制”BLOB。考虑字符集问题,这也许是有道理的
  • 我没有重新检查 2.1,但在最近的版本中,我知道没有这样的限制。 Blob 连接将适用于任何长度的文本 blob(子字符串和其他内容也是如此);我还没有检查二进制 blob。您提到的空行为是标准的,也适用于 varchar 连接。
  • 这个 NULL 行为当然是标准的,但不是主题启动者想要的,从他的问题和他自己现在删除的答案中使用 COALESCE 来判断。 @MarkRotteveel
【解决方案2】:

您遇到的主要问题是原始值是NULL。对NULL 值的加法、连接等操作将产生NULL。要深入了解NULL 的详细信息,请考虑阅读Firebird Null Guide

解决方案是当列为null*时使用COALESCE提供一个默认值(例如空字符串)。

UPDATE tablename
SET fieldTarget = COALESCE(fieldTarget, '') || :string
WHERE tablePk = :pkTarget;

*:你已经在你现在删除的答案中有这个,但是它被转换为 varchar 有点模糊,这不应该是必要的

【讨论】:

  • 我已经尝试过这种方式但返回此错误:SQL Error [335544454] [HY000]: filter not found to convert type 1 to type 2 [SQLState:HY000, ISC error code:335544454]
  • @gbragamonte 这意味着该字段不是文本 blob(又名 sub_type 1),而是应该仅用于 Firebird 内部用途的 blob sub_type 2 (BLR)(你甚至不应该能够定义该类型的 blob,但我不确定 Firebird 2.1 中是否已经存在这种保护)。
  • @gbragamonte 您可能想要解决问题并将 blob 重新创建为正确的类型之一,或者如果您认为它已经是 blob sub_type 文本(或 sub_type 1),那么它真的是有一个完全可重现的例子很有帮助。
  • @MarkRotteveel 至少在 FB2.5 中(但我相信任何 FB2.x)可以将 BLR-BLOB 转换为 VARCHAR,它调用 Firebird 的内置“反汇编器”来转换“已编译" 将字节码转换为或多或少可读的助记符。如果 BLR blob 可以转换为 varchar 但不能转换为 txt-blob,那就太奇怪了。附言也许不是字段,而是以某种方式获得子类型 2 的参数?
  • @Arioch'The 错误是关于从类型 1 到类型 2 的错误,这将在商店发生,而不是从类型 2 到类型 1。此外,OP 的执行方式(在 DBeaver 中)将导致在执行之前将值合并为文字,因此没有参数。我只能通过手动将字段的子类型设置为 2 来在 Firebird 2.1 中重现它(使用系统表更新,因为您无法在 2.1 中使用 DDL 创建类型 2 blob)。
【解决方案3】:

您可以尝试在 COALESCE 中使用 CAST("your blob null field" 作为 "MY BLOB DOMAIN OF SUBTYPE_1") 类型,它适用于我(在 firebird 2.1 中测试)

Firebird CAST

Firebird COALESCE

在我测试的情况下,我有一个“空”blob 字段(我们称他为“NOTES”),其中包含下一个域信息:

BLOB SUB_TYPE 0 段大小 80

执行COALESCE(NOTES, '') 会返回下一个错误:

数据类型在 COALESCE 表达式中不可比较

诀窍是创建一个 BLOB SUB_TYPE 1 的(我们称他为“TEXT”)并在 concat 或获取之前对该域进行 CAST:

SELECT COALESCE(CAST(NOTES AS TYPE OF TEXT), '') FROM MY_TABLE

在您的情况下,下一个情况必须正常工作:

UPDATE tablename
SET fieldTarget = COALESCE(CAST(:fieldTarget AS TYPE TEXT), '') || :string
WHERE tablePk = :pkTarget;

考虑在数据库中创建域 TEXT 作为 blob sub_type 1 之前。

PD:真正的诀窍是转换到要更新的字段的域。

【讨论】:

    猜你喜欢
    • 2016-05-11
    • 1970-01-01
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-13
    • 2011-04-17
    • 2021-01-14
    相关资源
    最近更新 更多