🌹欢迎来到《小5讲堂》🌹
🌹这是《Sql Server》系列文章,每篇文章将以博主理解的角度展开讲解。🌹
🌹温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!🌹
👨💻 作者简介🏆 荣誉头衔:2024博客之星Top14 | CSDN博客专家 | 阿里云专家博主
🎤 经历:曾多次进行线下演讲,亦是CSDN内容合伙人以及新星优秀导师
💡 信念:“帮助别人,成长自己!”
🚀 技术领域:深耕全栈,精通 .NET Core (C#)、Python、Java,熟悉主流数据库
🤝 欢迎交流:无论是基础概念还是进阶实战,都欢迎与我探讨!
目录
- 前言
- 问题现象
- 排查思路
- 第一步:检查数据类型
- 第二步:全匹配测试
- 第三步:排除隐藏字符
- 根本原因:排序规则差异
- Windows vs Linux Docker 默认排序规则
- 为什么会匹配失败?
- 解决方案
- 方案一:查询加 N 前缀(推荐)
- 方案二:修改数据库排序规则(治本)
- 经验总结
- 参考
- 文章推荐
前言
经常使用linux服务器的朋友可能会知道nvarchar和varchar的本质区别,对于博主最近才接触linux服务器来说,还是会才一点坑。
原来nvarchar匹配查询中文数据时,需要加一个N在前面,否则无法查询到数据,真是这十年开发经验白学了,现在才知道,必须给自己两巴掌反省反省。
SQL Server迁移Linux Docker:NVARCHAR查询为何失灵?
注意,如果是@title参数化就无需加N
还有个情况,就是varchar保存了中文,但是在导入linux系统的mssql后,出现了??问号
问题现象
SQL Server从Windows迁移到Linux Docker后,一条简单的查询语句返回了异常结果:
SELECTe_status_text,LEN(e_status_text),user_guidFROMmini_es_energyWHEREuser_guid='36f48dfd-a0c3-4277-8f38-eeb163953858'ANDe_status_textLIKE'%已到账%'明明表中有e_status_text = '已到账'的记录,但LIKE '%已到账%'就是匹配不到,而'待到账'、'已退款'等值却能正常显示。
更诡异的是,用LEN()和DATALENGTH()检查,长度和字节数都正常(3和6),没有任何隐藏字符。
排查思路
第一步:检查数据类型
SELECTDATA_TYPE,CHARACTER_MAXIMUM_LENGTHFROMINFORMATION_SCHEMA.COLUMNSWHERETABLE_NAME='mini_es_energy'ANDCOLUMN_NAME='e_status_text';结果:e_status_text为nvarchar(50)。
第二步:全匹配测试
改用=精确匹配依然查不到:
ANDe_status_text='已到账'-- 仍返回空第三步:排除隐藏字符
查看实际存储值及其长度:
SELECTe_status_text,LEN(e_status_text)AS长度,DATALENGTH(e_status_text)AS字节数FROMmini_es_energyWHEREuser_guid='36f48dfd-a0c3-4277-8f38-eeb163953858';结果完全正常:
| e_status_text | 长度 | 字节数 |
|---|---|---|
| 已到账 | 3 | 6 |
数据本身没问题,问题出在比较规则上。
根本原因:排序规则差异
Windows vs Linux Docker 默认排序规则
| 环境 | 默认排序规则 | 中文支持 |
|---|---|---|
| Windows Server | Chinese_PRC_CI_AS | ✅ 原生支持 |
| Linux Docker | SQL_Latin1_General_CP1_CI_AS | ❌ 不支持中文代码页 |
为什么会匹配失败?
- 字段
e_status_text是nvarchar(Unicode) - 查询字符串
'已到账'被当作varchar(非Unicode)处理 - 在 Linux Docker 的
Latin1排序规则下,varchar无法正确转换为nvarchar进行中文比较 - 导致字符匹配失败,查询返回空
简单说:nvarchar字段 +varchar条件 + Latin1 排序规则 = 中文匹配失效。
解决方案
方案一:查询加 N 前缀(推荐)
所有涉及中文/Unicode字符串的条件,统一加N前缀,显式声明为 Unicode:
SELECTe_status_text,LEN(e_status_text),user_guidFROMmini_es_energyWHEREuser_guid='36f48dfd-a0c3-4277-8f38-eeb163953858'ANDe_status_text=N'已到账';-- = 匹配-- 或ANDe_status_textLIKEN'%已到账%';-- 模糊匹配优点:立即生效,无需停机,符合SQL Server最佳实践,跨环境兼容。
方案二:修改数据库排序规则(治本)
将数据库排序规则改为中文支持的规则(需停机维护):
-- 查看当前排序规则SELECTname,collation_nameFROMsys.databasesWHEREname='你的数据库名';-- 修改为中文排序规则(需单用户模式)ALTERDATABASE你的数据库名COLLATEChinese_PRC_CI_AS;⚠️注意:此操作会影响所有字符串比较,需重建部分索引,生产环境请谨慎操作。
经验总结
nvarchar字段配N前缀是最佳实践,无论在Windows还是Linux都应如此。- 跨平台迁移时,排序规则差异是常见陷阱,Windows上的“侥幸成功”不代表Linux上也能跑。
- 迁移前检查排序规则:
SELECTSERVERPROPERTY('Collation')ASServerCollation; - 如果无法修改代码,可在迁移时指定与Windows一致的排序规则来避免此问题。
参考
- SQL Server Collation 官方文档
- Linux 上 SQL Server 的排序规则设置
文章推荐
【数据库】记录一次sql server在windows和linux服务器下安装,对于数据类型varchar和nvarchar的明显区别,你是否也遇到过中文匹配无法查询到数的情况
【数据库】Sql Server,A表的a字段更新到B表的a字段,基础知识点,一分钟拿下
【数据库】Sql Server数据库中isnull、iif、case when三种方式的使用和空值判断
【数据库】如何使用一款轻量级数据库SqlSugar进行批量更新,以及查看最终的Sql操作语句
【数据库】使用Sql Server将分组后指定字段的行数据转为一个字段显示,并且以逗号隔开每个值,收藏不迷路
【数据库】SQL Server 查询条件小技巧:ISNULL 函数的使用,有请DeepSeek来辅助讲解下
【Sql Server】在SQL Server中生成雪花ID(Snowflake ID)
【Sql Server】使用row_number over方式进行表分页,数据量达到五千多条记录后,查询变慢需要20多秒的解决方案
【Sql Server】随机查询一条表记录,并重重温回顾下自定义函数的封装和使用
【Sql Server】锁表如何解锁,模拟会话事务方式锁定一个表然后进行解锁
【Sql Server】通过Sql语句批量处理数据,使用变量且遍历数据进行逻辑处理
【新星计划回顾】第六篇学习计划-通过自定义函数和存储过程模拟MD5数据
【新星计划回顾】第四篇学习计划-自定义函数、存储过程、随机值知识点
【Sql Server】Update中的From语句,以及常见更新操作方式
总结:温故而知新,不同阶段重温知识点,会有不一样的认识和理解,博主将巩固一遍知识点,并以实践方式和大家分享,若能有所帮助和收获,这将是博主最大的创作动力和荣幸。也期待认识更多优秀新老博主。