我有一个包含多语言CompanyName列的公司表(定义为nvarchar(512))。
我还有一个存储过程来搜索并返回公司列表,它需要2个nvarchar参数 - 一个是搜索词,另一个是ISO语言代码。
我希望能够做的是返回搜索结果,该搜索结果使用与第二个参数中提供的语言代码相对应的排序规则排序,例如:
SELECT * FROM dbo.Companies WHERE CompanyName LIKE '%searchstring%'
ORDER BY
CASE @lang
WHEN 'sv' THEN CompanyName COLLATE Sami_Sweden_Finland_100_CI_AI
WHEN 'ch' THEN CompanyName COLLATE Chinese_Simplified_Pinyin_100_CI_AI
ELSE CompanyName
END
但是当我尝试运行它时出现以下错误:
无法解决排序规则冲突 之间 “Chinese_Simplified_Pinyin_100_CI_AI” 和“Sami_Sweden_Finland_100_CI_AI”中 CASE操作。
这对我来说毫无意义 - 这不像我在整理排序,为什么会出现整理冲突?这是一个相互排斥的选择。
我已经尝试过不聪明并且只是使用动态sql,遗憾的是,这似乎是让数据库无法缓存执行计划,因此查询时间超过20秒(而不是1)表包含大约200万行。
我确信文化敏感排序必须是一个常见问题,是否有人知道一个不涉及改变当前模式的好解决方案(即必须创建其他列)?
答案 0 :(得分:2)
Acolumn只能有一个排序规则。 CASE意味着你试图让多个相互冲突。试试这个:
SELECT * FROM dbo.Companies WHERE CompanyName LIKE '%searchstring%'
ORDER BY
CASE @lang
WHEN 'sv' THEN CompanyName ELSE '' END
END COLLATE Sami_Sweden_Finland_100_CI_AI,
CASE @lang
WHEN 'ch' THEN CompanyName ELSE '' END
END Chinese_Simplified_Pinyin_100_CI_AI
答案 1 :(得分:2)
好的,我终于找到了答案,感谢@gbn,鉴于我对问题的初步定义,你的解决方案肯定是正确的。
但事实证明,我的工作是错误的假设,即应该避免使用动态SQL。为了实现这一点,我必须添加一个值为
的计算(和索引)列CompanyName COLLATE [Collation_Name]
对于我需要排序的每个排序规则(我意识到我在原始问题中说过我不想改变模式,但我真正的意思是我不想移动现有数据)。
运行以下查询时
EXEC('SELECT TOP 10 * FROM dbo.Companies
WHERE CompanyName LIKE ''%searchstring%''
ORDER BY CompanyName COLLATE ' + @collation)
查询引擎在关联的计算列上获取索引,并得到快速响应。不幸的是,当使用@gbn提供的查询时,将忽略在计算列上创建的索引,从而导致性能下降。
这对我来说非常令人惊讶,因为我一直认为动态SQL是一种应该避免的邪恶,除非绝对必要(即当你的查询以你无法参数化的方式变化时)