PostgreSQL sql文件编码引起的数据导入乱码或查询字符集异常报错(invalid byte sequence)...

本文探讨了当用户客户端与服务端字符集不匹配时,如何处理多字节字符(如中文)出现的乱码问题。通过实例展示了在不同编码环境下,如UTF8和SQL_ASCII之间的数据转换过程及可能遇到的异常情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景
当用户客户端字符集与服务端字符集不匹配时,写入的多字节字符(例如中文)可能出现乱码。

例子
数据库字符集为sql_ascii,允许存储任意编码字符。

digoal@pg11-320tb-zfs-> psql
psql (11beta4)
Type "help" for help.

postgres=# l+

                                                             List of databases  
NameOwnerEncodingCollateCtypeAccess privilegesSizeTablespaceDescription
postgrespostgresSQL_ASCIICen_US.utf8 140 TBpg_defaultdefault administrative connection database
template0postgresSQL_ASCIICen_US.utf8=c/postgres +15 MBpg_defaultunmodifiable empty database
postgres=CTc/postgres
template1postgresSQL_ASCIICen_US.utf8=c/postgres +15 MBpg_defaultdefault template for new databases

(3 rows)
客户端为utf8编码

digoal@pg11-320tb-zfs-> echo $LANG
en_US.utf8
编辑一个文件,以UTF8编码

vi test.sql

insert into tbl values (1, '你好');
内容如下

digoal@pg11-320tb-zfs-> cat test.sql
insert into tbl values (1, '你好');
编码如下

digoal@pg11-320tb-zfs-> file test.sql
test.sql: UTF-8 Unicode text
转换为GBK,写入数据库

digoal@pg11-320tb-zfs-> iconv --help
Usage: iconv [OPTION...] [FILE...]
Convert encoding of given files from one encoding to another.

Input/Output format specification:
-f, --from-code=NAME encoding of original text
-t, --to-code=NAME encoding for output

Information:
-l, --list list all known coded character sets

Output control:
-c omit invalid characters from output
-o, --output=FILE output file
-s, --silent suppress warnings

  --verbose              print progress information  

-?, --help Give this help list

  --usage                Give a short usage message  

-V, --version Print program version

Mandatory or optional arguments to long options are also mandatory or optional
for any corresponding short options.

For bug reporting instructions, please see:
http://www.gnu.org/software/libc/bugs.html.

digoal@pg11-320tb-zfs-> iconv -f UTF8 -t GBK test.sql|psql -f -
INSERT 0 1
或者这样写入(client_encoding和server都设置为sql_ascii时,不检查编码合法性,直接存入数据库)

digoal@pg11-320tb-zfs-> iconv -f UTF8 -t GBK test.sql -o test.sql.gbk

digoal@pg11-320tb-zfs-> psql
psql (11beta4)
Type "help" for help.

postgres=# set client_encoding =sql_ascii;
SET
postgres=# i ./test.sql.gbk
INSERT 0 1
当设置客户端client_encoding为utf8编码时,由于存入的数据编码不合法,导致查询异常

digoal@pg11-320tb-zfs-> psql
psql (11beta4)
Type "help" for help.

postgres=# set client_encoding =utf8;
SET
postgres=# select * from tbl;
ERROR: invalid byte sequence for encoding "UTF8": 0xc4 0xe3
当client_encoding设置为GBK编码,查询为乱码

postgres=# set client_encoding =gbk;
SET
postgres=# select * from tbl;

idinfo
1?oí

参考
《PostgreSQL 多字节字符集合法性检测》

《[转] SqlServe到PG迁移错误:无效的编码序列"UTF8": 0x00》

《PostgreSQL UTF8 和 GB18030编码map文件不完整的问题》

《PostgreSQL WHY ERROR: invalid byte sequence for encoding "UTF8"》

《PostgreSQL SQL_ASCII encoding introduce》

《PostgreSQL Server Encoding sql_ascii attention》
转自阿里云德哥

### PostgreSQLUTF8 到 EUC_CN 编码转换问题 当执行从 UTF8 到 EUC_CN 的编码转换,可能会遇到特定字符无法正确映射的情况。对于错误 `ERROR: invalid byte sequence for encoding "UTF8": 0xe5 0xbd 0xa7`,这通常意味着该字节序列在目标编码中不存在有效表示。 #### 解决方案概述 一种常见的解决方案是在数据传输之前清理替换掉那些可能导致问题的特殊字符。具体来说,在处理过程中可以采用以下几种策略: 1. **调整客户端和服务端编码配置** 如果可能的话,尝试统一客户端与服务器之间的字符集设置。通过查询系统视图确认当前环境下的编码情况: ```sql SELECT name, setting FROM pg_settings WHERE name LIKE 'client_encoding'; ``` 2. **预处理输入数据** 对于已知会引发冲突的具体字符(如本案例中的 `\uE5BD\uA7`),可以在应用程序层面提前过滤这些字符。例如使用正则表达式其他字符串操作函数来移除非法字符组合。 3. **利用转义机制** 当直接修改原始数据不可行,则考虑启用某些形式的数据转义选项。PostgreSQL 提供了一个名为 `escape_string_warning` 的参数用于控制是否警告关于潜在危险的反斜杠 (`\`) 使用;另外还有 `standard_conforming_strings` 参数影响着标准兼容性的行为模式[^3]。 4. **自定义字符映射规则** 针对特别棘手的情形下,还可以编写自定义逻辑实现更精细粒度上的字符替换工作。比如创建一个 PL/pgSQL 函数来进行逐个字符级别的检查并应用相应的替代措施。 ```plpgsql CREATE OR REPLACE FUNCTION clean_utf8_for_euc_cn(text) RETURNS text AS $$ DECLARE result TEXT := ''; BEGIN FOR i IN 1..length($1) LOOP IF ascii(substring($1 FROM i FOR 1)) NOT BETWEEN 128 AND 255 THEN result := result || substring($1 FROM i FOR 1); ELSEIF encode(convert_to(substring($1 FROM i FOR 1), 'LATIN1'), 'hex') != 'e5bda7'::text THEN -- Only allow characters that can be safely converted to EUC_CN result := result || convert_from(convert_to(substring($1 FROM i FOR 1), 'LATIN1'), 'EUC_CN'); END IF; END LOOP; RETURN result; END; $$ LANGUAGE plpgsql IMMUTABLE STRICT; ``` 此代码片段展示了一种简单的方法来遍历给定文本串内的每一个字符,并仅保留能够安全地被转换为目标编码格式的部分。请注意实际部署前需根据具体情况调整细节部分。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值