SQL Server插入中文乱码的核心原因是客户端声明、字段类型、排序规则三者未对齐;必须同时确保INSERT加N前缀、字段为nvarchar、Collation匹配中文且客户端显式指定编码,缺一不可。

SQL Server插入中文乱码,核心问题不是“数据库坏了”,而是字符编码路径上某处断了——客户端声明、字段类型、排序规则(Collation)三者没对齐。只改一个地方,大概率白忙。
INSERT 语句必须加 N 前缀才能存中文
这是最轻量、最常被忽略的修复点。哪怕字段是 nvarchar,不加 N,SQL Server 就当它是普通 varchar 字符串处理,走默认单字节编码(比如 Latin1_General_CI_AS),中文直接变 ???。
-
INSERT INTO users (name) VALUES ('张三')→ 很可能乱码 -
INSERT INTO users (name) VALUES (N'张三')→ 正确:N明确告诉 SQL Server 这是 Unicode 字符串 - 存储过程参数也一样:参数定义为
@name nvarchar(50),调用时仍要传N'张三',否则传入瞬间就转义失败
varchar 字段存中文必踩坑,优先换 nvarchar
varchar 是单字节编码,依赖 Collation 指定的代码页(如 Chinese_PRC_CI_AS 对应 CP936/GBK)。但一旦客户端或连接层没匹配该代码页,或跨库迁移,极易断裂。而 nvarchar 原生 Unicode,兼容性高得多。
- 建表时直接用
nvarchar:例如name nvarchar(100),别写varchar(100) - 已有
varchar字段想改?别只改类型:先ALTER TABLE t ALTER COLUMN name nvarchar(100),再确认数据是否已损坏;若已乱码,需从备份或原始源重新导入 - 注意:
nvarchar占用空间翻倍(2 字节/字符),但换来的是确定性——不用操心客户端用什么编码
Collation 不匹配会导致“看起来正常,其实已损坏”
字段是 nvarchar 且语句加了 N,但查询出来还是乱码?大概率是数据库或字段级 Collation 和中文预期不符。比如服务器默认是 Latin1_General_CI_AS(代码页 1252),而你期望它按 GBK(代码页 936)解释 varchar 数据——这根本不可靠。
- 查当前数据库 Collation:
SELECT DATABASEPROPERTYEX('your_db', 'Collation') - 查字段 Collation:
SELECT collation_name FROM sys.columns WHERE object_id = OBJECT_ID('your_table') AND name = 'your_column' - 新建数据库时指定:
CREATE DATABASE mydb COLLATE Chinese_PRC_CI_AS - 改现有数据库(需先切单用户模式):
ALTER DATABASE mydb SET SINGLE_USER WITH ROLLBACK IMMEDIATE; ALTER DATABASE mydb COLLATE Chinese_PRC_CI_AS; ALTER DATABASE mydb SET MULTI_USER; - 注意:改数据库 Collation 不会自动更新已有
varchar字段的实际存储值,只影响新创建对象和比较行为
Python / JDBC / Navicat 等客户端必须显式声明编码
即使数据库、表、字段全设对了,客户端连上来没声明字符集,SQL Server 仍按默认(通常是 Latin1)解析请求。这时 N'中文' 能救,但普通字符串和参数绑定依然崩。
- Python + pyodbc:
conn = pyodbc.connect("DRIVER={ODBC Driver 17 for SQL Server};SERVER=...;DATABASE=...;UID=...;PWD=...;CHARSET=UTF8")—— 注意部分驱动支持CHARSET=UTF8,更推荐用unicode=True参数 - Python + pymssql:
conn = pymssql.connect(..., charset='cp936')(Windows)或'utf-8'(Linux/macOS,取决于 SQL Server 版本) - JDBC URL 加参数:
jdbc:sqlserver://host:port;databaseName=db;characterEncoding=utf-8;sendStringParametersAsUnicode=true - Navicat:连接属性 →「高级」→ 勾选「使用 Unicode」,或在「初始化命令」里加
SET NAMES utf8(不通用,优先选前者)
真正麻烦的从来不是“怎么改”,而是“改哪几处”。漏掉 N 前缀、漏掉客户端 charset、漏掉字段类型,任意一个都会让前面所有努力失效。线上环境尤其要注意:改 Collation 会锁库,改大表字段类型可能阻塞业务,动手前务必验证备份可恢复。

















