我只想将 SQL 列中每个句子的每个单词的第一个字母大写。
例如,如果句子是:
'我喜欢电影'
然后我需要输出:
《我喜欢电影》
询问:
declare @a varchar(15)
set @a = 'qWeRtY kEyBoArD'
select @a as [Normal text],
upper(@a) as [Uppercase text],
lower(@a) as [Lowercase text],
upper(left(@a,1)) + lower(substring(@a,2,len(@a))) as [Capitalize first letter only]
在这里,我只在我的专栏中做了大写、小写和大写首字母(这里我只放了一个随机单词)。
这是我的结果:
有没有可能这样做?
在不使用用户定义函数的情况下是否有可能获得结果?
我需要输出Qwerty Keyboard
这首先通过用空标记替换所有空格将字符串转换为 XML
<X/>
。然后它使用nodes()
. 为了让行恢复到一个值,它使用了这个for xml path
技巧。在 SQL Server 2016 中,您可以使用 R 执行此操作,例如
你是否应该是一个不同的问题:)
也许我很傻,但是检查了我针对提供的某些内容编写的以下查询,这似乎更有效(取决于索引)。
代码有点愚蠢,但没有人说如果它看起来很愚蠢但它有效,那么它并不愚蠢。
另一种选择是通过 SQLCLR 处理此问题。.NET 中甚至已经有一种方法可以执行此操作:TextInfo.ToTitleCase(in
System.Globalization
)。此方法将大写每个单词的第一个字母,并将剩余的字母小写。与这里的其他提议不同,它还跳过所有大写的单词,假设它们是首字母缩略词。当然,如果需要这种行为,也可以很容易地更新任何 T-SQL 建议来执行此操作。.NET 方法的一个好处是它可以大写字母作为补充字符。例如:DESERET SMALL LETTER OW具有DESERET CAPITAL LETTER OW的大写映射 (当我将它们粘贴到此处时,两者都显示为框),但该
UPPER()
函数不会将小写版本更改为大写,即使当当前数据库的默认排序规则设置为Latin1_General_100_CI_AS_SC
. 这似乎与 MSDN 文档一致,该文档未列出使用Collation: CollationUPPER
and Unicode Support: Supplementary Characters时行为不同的函数图表。LOWER
_SC
返回(放大以便您可以实际看到补充字符):
您可以使用 Unicode.org 上的以下搜索功能查看小写字符的完整(和当前)字符列表并更改为大写字符(您可以通过向下滚动来查看补充字符,直到您到达“DESERET”部分,或者只是点击Control-F并搜索该单词):
http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AChanges_When_Titlecased%3DYes%3A%5D
虽然老实说,这并不是一个巨大的好处,因为任何人实际上都在使用任何可以标题的补充字符是值得怀疑的。无论哪种方式,这是 SQLCLR 代码:
这是@MikaelEriksson 的建议——稍作修改以处理
NVARCHAR
数据以及跳过全部大写的单词(以更接近地匹配 .NET 方法的行为)——以及对该 T-SQL 实现和SQLCLR 实现:行为上的另一个区别是这个特定的 T-SQL 实现仅在空格上拆分,而该
ToTitleCase()
方法将大多数非字母视为单词分隔符(因此在处理“one&TWO”部分时存在差异)。两种实现都正确处理组合序列。“üvÜlA”中的每个重音字母都由一个基本字母和一个组合分音符号/变音符号(每个字母上方的两个点)组成,并且在两个测试中它们都正确转换为另一种情况。
最后,SQLCLR 版本的一个意想不到的缺点是,在进行各种测试时,我在 .NET 代码中发现了一个与处理带圆圈字母相关的错误(现已在 Microsoft Connect 上报告——更新:Connect 已经移至
/dev/null
- 从字面上看 - 所以如果问题仍然存在,我可能需要重新提交)。.NET 库将带圆圈的字母视为单词分隔符,这就是它没有将“ⓐDDD”转换为“Ⓐddd”的原因。供参考
TextInfo.ToTitleCase
封装上述方法的预先完成的 SQLCLR 函数现在可以在SQL#(我编写的)的免费版本中作为String_ToTitleCase和String_ToTitleCase4k 获得。?
作为Mikael Eriksson 的答案的替代方案,您可以考虑在多行选择语句中使用专有的 T-SQL 处理变量设置。
在 SQL Server 中,当变量被设置为 SELECT 语句的一部分时,每一行都将执行设置逻辑的迭代。
人们经常使用这种方法来连接字符串,尽管它不受支持并且存在一些官方记录的问题。官方问题与特定的 ORDER BY 特征有关,我们在这里不需要,所以也许这是一个安全的选择。
在这里,我们遍历字母表中的 26 个字母,如果它们前面有空格,则将它们替换为大写版本。(我们最初通过将第一个字母大写并使其余字母小写来准备字符串,就像您在问题中所做的那样。)
SQL 有点复杂,因为它需要使用一个 Tally 表(一个数字表)来生成它正在执行的 26 次替换迭代。您可以制作一个方便的内联表值用户定义函数 (TVF) 来生成该数字表,或者您甚至可以使用物理表。
此选项的一个缺点是它不能成为内联 TVF 的一部分,因为它需要涉及设置变量。因此,如果您想将此方法应用于输出的列,则需要将其包装到多语句 TVF 或标量用户定义函数中。
但是,它的查询计划要简单得多,而且可能比 XML 方法快得多。您可能会争辩说它也更容易理解(特别是如果您有自己的计数表)。
(我使用更大的字符串对此进行了测试,XML 解决方案大约为 6 毫秒,而 14 毫秒。)
此解决方案还有许多其他限制。如所写,它假定不区分大小写的排序规则,尽管您可以通过指定排序规则或在搜索词上运行 LCASE 来消除该问题,但会牺牲一些性能。它也只处理标准的 ASCII 字母并且依赖于它们在字符集中的位置,所以它不会对 ñ 做任何事情。
假设您只想在空格后面大写单词,这是另一种方法。
可能不是防弹的,但我希望它对这个线程有帮助。
下面是我在 Firebird 数据库中执行此操作的过程。可能可以清理很多,但它为我完成了工作。
递归 CTE 非常适合这类事情。
对于大型操作可能不是特别有效,但确实允许在纯 SQL 选择语句中进行这种操作:
输出:
我喜欢这个版本。它很简单,并且可以用来创建一个函数,你只需要拥有正确的 SQL Server 版本: