我很难确定一个问题,这个问题似乎与Postgres数据库中存在的奇怪字符有关.我正在使用Java从postgres中提取数据并将其加载到BigQuery中.偶尔我会注意到,有些价值观似乎在这个过程中无缘无故地发生了变化.仔细判断后,我发现在所有情况下,这个问题似乎都是由我认为不正常的角色引起的.

Postgres数据库编码为UTF-8.Java编码也是UTF-8.

下面是我所看到的一个例子:

我有一个文本字段,其中包含以下值:SÅ‚awomir.

If I run this SQL:
select length('SÅ‚awomir')

我得到的值是9,看起来是正确的.但是,如果我将该字符串导出到文本文件中并在十六进制编辑器(在我的例子中使用十六进制编辑器扩展名为Visual Studio代码)中查看它,则该字符串的长度看起来是11,而不是9.仔细判断后,第二个和第三个字符由两个十六进制值表示,而不是像其他字符那样只有一个十六进制值.这些第二个和第三个字符由以下4个十六进制值表示:

C3 85 C2 82

Here's a screenshot of the HEX editor showing those characters. As you can see, the string seems to have 11 characters, not 9: enter image description here

请帮我理解这些角色是什么,我能做些什么.它们是有效的UTF-8字符吗?如果是这样,为什么它们应该被Java程序转换,我如何才能阻止这种情况发生?

更新2023-10-31:感谢您@Laurenz Albe的回复.它很好地解释了所发生的事情(以及future 如何防止它),但我不确定它是否完全解决了我的问题,因为我没有能力控制将数据插入数据库的upstream 过程.

我还有几个相关的细节:

我们使用Google数据流从Postgres中提取数据并将其移动到BigQuery.当数据到达BigQuery时,它看起来与Postgres中的完全一样(这正是我想要的).当我使用Java(JDBC)从BigQuery中取出该值,然后将其插入到另一个BigQuery表中时,问题实际上就发生了.

我不是像"INSERT INTO...SELECT FROM.."这样的单一INSERT语句.在这种情况下,数据永远不会离开BigQuery.我所做的是首先获取数据,并将结果赋给一个Java变量.然后,在第二步中,我将该值插入到另一个BigQuery表中.当我这样做时,目标表中的数据会发生轻微的更改,所以我正在try 找出如何防止这种情况发生.

以下是原始值和移动到另一个表后的值的示例:

enter image description here

下面是我HEX查看器中相同文件的屏幕截图:

enter image description here

正如您所看到的,该值已发生了一些更改-新值似乎为c3 85 e2 80 9a

因此,我真正的问题是,我如何才能保留原始价值?在将数据放入Java然后再放回BigQuery的过程中似乎发生了一些事情.我的Java环境配置为使用UTF8编码,因此我对如何保留原始值感到有点困惑.

推荐答案

这是一个"双重编码"的例子.

原来的字符串一定是"SłAvomir".第二个字母(ł)用UTf-8中的两个字节C582编码.

现在,当UTF-8编码的字符串被插入到数据库中时,有人将PostgreSQL客户端编码设置为单字节编码,可能是拉丁文1.因此,PostgreSQL将这两个字节解释为单独的字符:C5是"ä",82是一个无法打印的字符,控制字符的名称是"Break Allowed Here".

PostgreSQL将这两个字符转换为编码为UTF-8的服务器,服务器将它们转换为您观察到的四个字节.每个字符在UTF-8中由两个字节表示.

在转换为BigQuery的过程中,"允许在此中断"字符被转换为"curl 引号"(,).必须发生的事情是:

  • 数据是通过客户端编码拉丁文-1提取的,因此结果为C582

  • 客户端被插入到BigQuery中,客户端编码为WINDOWS-1252,其中82表示curl 引号

  • BigQuery服务器将curl 引号转换为ZTF-8,最后得到E2809A


总而言之:

  • 您的PostgreSQL数据库中的原始数据已损坏,因为导入数据时将client_encoding设置为LATIN1,而不是UTF8

  • 在传输到BigQuery期间,数据被进一步 destruct ,因为BigQuery客户端编码被设置为WINDOWS-1252

Postgresql相关问答推荐

PostgreSQL权限如何工作?需要从表格中 Select 收件箱

PostgreSQL按描述请求

PostgreSQL存储过程中不存在游标

使用postgres在go测试容器中使用tern迁移

将整数(以毫秒为单位的epoch时间)转换为PrimitiveDateTime

在 Windows 上使用 rsync 进行 Postgresql 副本升级

如何在docker-compose中使用docker secrets设置ConnectionString?

在连接字符串并将其附加到 PostgreSQL 中的 where 子句时出现语法错误.怎么修?

Docker compose read connection reset by peer error on pipeline

Postgresql:创建默认表空间的视图和使用?

postgresql中的外键可以被触发器违反

如何让 Rails 使用 SSL 连接到 PostgreSQL?

Redis 可以写出到像 PostgreSQL 这样的数据库吗?

与 Oracle 的 CONNECT BY ... START WITH 等效的 PostgreSQL 语法是什么?

如何语法判断 PostgreSQL 配置文件?

错误:表tablename上的更新或删除违反外键约束

在 postgres 中存在不同的 string_agg 问题

使用 Spring、Hibernate 和 C3P0 管理多租户 Web 应用程序中的连接池

错误:索引表达式中的函数必须在 Postgres 中标记为 IMMUTABLE

错误:无法在只读事务中执行 CREATE TABLE