【问题标题】:How to determine the character set of a Firebird database如何确定 Firebird 数据库的字符集
【发布时间】:2021-09-24 07:26:47
【问题描述】:

我已经阅读了following thread,并且能够制作一个转换脚本(基于 C#),将我所有的charset=NONE 数据库转换为charset=UTF8,并且大部分都很好用(我还有一些特别的字符转换为奇怪符号的情况,但这是边缘的)。

我的问题是我有很多 备份数据库 文件 (*.fbk),我不确定这是 UTF8 还是 @ 987654327@。在理想情况下,我的代码将根据fbk 文件的格式从文件中恢复数据库后处理转换,因此我只在必要时和恢复后进行转换。

这有可能吗?或者有没有办法在恢复数据库时定义charset(通过gback或通过ADO.NET提供程序)?

【问题讨论】:

  • 您要解决的具体问题是什么?数据库本身没有字符集(除了其默认字符集,仅在创建没有显式字符集的新列时使用)。每一列都有一个字符集,每一列都可以有不同的字符集。简而言之,没有通用的方法来确定这一点。
  • 没有万能的数据库字符集,实际上每一列都有自己的。此外,当您像all my charset=NONE databases to charset=UTF8 那样说话时,它听起来不是“数据库字符集”而是“连接字符集”,这是一种不同的野兽,尽管有一些关系。您也可以在topanswers.xyz/databases?q=1462的右侧面板(cmets)中阅读更多讨论和一些查询
  • 好的,我的默认字符集在任何地方都是“NONE”,因为这是遗留的。在当前状态下,我需要UTF8,所以我必须将所有数据库转换为包含UTF8 数据。正如我发现的那样,这将简化客户端上的很多事情......但是有十几个数据库文件需要我自动化这个过程......
  • 你最好做“数据泵送”,创建仅元数据的纯骨架数据库,为列和应用程序的连接设置字符集,打开两个新旧数据库并逐行复制表。您必须弄清楚这些表的顺序,或者有时这些表中的行,分析依赖关系。像 IBExpert(可能还有其他)这样的工具确实具有“将元数据提取到 SQL 脚本”功能,该功能的正确性和现代性只有通过测试才能知道,但对于简单的 DB,它可以工作
  • 您需要查询系统表以获取此信息,因此您需要有一个正常运行的数据库来做出此决定。您不能从备份文件本身执行此操作(或者至少,这样做需要您以类似于 gbak 将其还原为数据库的方式自己解析文件)。所以是的,您需要恢复数据库才能执行此操作。现在是否需要再次备份取决于您的流程。

标签: c# character-encoding firebird database-backups firebird-.net-provider


【解决方案1】:

一般来说,Firebird 数据库没有单一的字符集。每一列都可以有自己的字符集。所以你唯一能做的就是尝试使用启发式算法。

  1. 使用数据库默认字符集。需要明确的是,数据库默认字符集仅在未指定显式字符集时创建新列时使用。数据库完全有可能使用默认字符集 UTF8,而所有列都有字符集 WIN1251!

    您可以通过以下查询找到数据库默认字符集:

    select RDB$CHARACTER_SET_NAME from RDB$DATABASE 
    

    注意:如果结果为NULL,则表示默认字符集为NONE。

  2. 统计 CHAR、VARCHAR 和 BLOB SUB_TYPE TEXT 列的不同字符集,看看哪个出现最多:

    select 
      coalesce(cs.RDB$CHARACTER_SET_NAME, 'NONE') as CHARSET, 
      count(*) as CHARSET_COUNT
    from RDB$RELATIONS r
    inner join RDB$RELATION_FIELDS rf
      on rf.RDB$RELATION_NAME = r.RDB$RELATION_NAME
    inner join RDB$FIELDS f 
      on f.RDB$FIELD_NAME = rf.RDB$FIELD_SOURCE
    left join RDB$CHARACTER_SETS cs
      on cs.RDB$CHARACTER_SET_ID = f.RDB$CHARACTER_SET_ID 
    where coalesce(r.RDB$SYSTEM_FLAG, 0) = 0
    and r.RDB$VIEW_BLR is null
    and (f.RDB$FIELD_TYPE in (14, 37) or f.RDB$FIELD_TYPE = 261 and f.RDB$FIELD_SUB_TYPE = 1)
    group by 1
    order by 2 desc
    

顺便说一句,请注意,如果客户端使用了连接字符集 NONE,那么一列内容的实际字符集完全有可能与该列的定义字符集不匹配。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-11
    • 1970-01-01
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-20
    相关资源
    最近更新 更多