T-SQL中基于函数使用COLLATE的方法及排序异常排查
帮你搞定SQL排序规则的问题
首先得澄清两个关键的误解,这是导致你遇到问题的核心:
1. 关于调试的认知偏差
你以为调用函数后会返回带COLLATE字样的字符串,但实际上COLLATE根本不是字符串内容的一部分——它是SQL Server用来定义字符串排序/比较规则的属性标记,不会改变字符串本身的文字。所以你的调试代码返回Test是完全正常的,因为函数只是给这个字符串“打了个标记”,告诉SQL Server用指定的规则来处理它,而不是把COLLATE ...拼到字符串里。
另外你的调试代码还有个小bug:@p = Test没加单引号,SQL Server会把Test当成对象名,大概率会报错。正确的调试写法应该是:
DECLARE @l nvarchar(255) DECLARE @P nvarchar(255) = 'Test' SET @l = dbo.fnsConvert(@p = @P, @c = 'sv-SE'); -- 可以额外查看字符串的排序规则属性 SELECT @l, COLLATIONPROPERTY(CAST(SERVERPROPERTY('Collation') AS nvarchar), 'CodePage')
2. 排序结果不符合预期的原因
你用函数排序得到的结果不对,问题出在函数返回值的排序规则没有被正确保留。SQL Server中,函数返回值的排序规则默认会继承数据库的默认规则,哪怕你在函数内部给变量设置了COLLATE,返回时这个属性会被覆盖掉。也就是说,你的函数返回的字符串其实还是用的数据库默认排序规则,根本没用到你指定的瑞典语规则,自然排序结果不对。
两种靠谱的解决方案
方案一:直接在ORDER BY里指定排序规则(强烈推荐)
没必要绕函数,直接在排序环节指定规则,简单高效还不容易出错:
SELECT Title FROM Things ORDER BY Title COLLATE Finnish_Swedish_100_CI_AS
方案二:修改函数,强制指定返回值的排序规则
如果你一定要用函数,必须在RETURNS子句里显式指定排序规则,这样才能让返回值的规则生效:
CREATE FUNCTION [dbo].[fnsConvert] ( @p NVARCHAR(2000), @c NVARCHAR(2000) ) RETURNS NVARCHAR(2000) COLLATE Finnish_Swedish_100_CI_AS -- 这里显式指定返回规则 AS BEGIN IF ( @c = 'sv-SE' ) SET @p = @p COLLATE Finnish_Swedish_100_CI_AS ELSE SET @p = @p COLLATE SQL_Latin1_General_CP1_CI_AS RETURN @p END
不过要注意:这种方式返回值的排序规则是固定的,ELSE分支的设置可能会被覆盖,所以如果需要动态切换规则,方案一还是更灵活的选择。
额外小提示
- 排序规则只影响排序、比较的逻辑,不会改变字符串的实际内容——你看到的乱码(
A脜脛BC脰)大概率是客户端和数据库的编码不匹配导致的,和排序规则本身无关。 - 要验证排序规则是否生效,可以做个简单对比测试:
-- 不同规则下的排序结果差异 SELECT 'Ä' AS Char UNION SELECT 'A' UNION SELECT 'Ö' ORDER BY Char COLLATE SQL_Latin1_General_CP1_CI_AS -- 结果:A, Ä, Ö ORDER BY Char COLLATE Finnish_Swedish_100_CI_AS -- 瑞典语规则下:A, Ö, Ä
内容的提问来源于stack exchange,提问作者Gabriel Smoljar
相关产品推荐
相关产品推荐

