Otra opción es manejar esto a través de SQLCLR. Incluso hay un método disponible en .NET que hace esto: TextInfo.ToTitleCase (in System.Globalization
). Este método pondrá en mayúscula la primera letra de cada palabra y en minúscula las letras restantes. A diferencia de las otras propuestas aquí, también omite las palabras en mayúsculas, asumiendo que son siglas. Por supuesto, si se desea este comportamiento, sería bastante fácil actualizar cualquiera de las sugerencias de T-SQL para hacerlo también.
Una ventaja del método .NET es que puede poner letras mayúsculas que son caracteres suplementarios. Por ejemplo: DESERET SMALL LETTER OW tiene una asignación en mayúsculas de DESERET CAPITAL LETTER OW (ambas aparecen como cuadros cuando las pego aquí) , pero la UPPER()
función no cambia la versión en minúsculas a mayúsculas, incluso cuando La clasificación predeterminada para la base de datos actual está establecida en Latin1_General_100_CI_AS_SC
. Esto parece coherente con la documentación de MSDN que no aparece en la lista UPPER
y LOWER
en el cuadro de funciones que se comportan de manera diferente cuando se utiliza una _SC
Clasificación: Compatibilidad y Soporte Unicode: Caracteres suplementarios .
SELECT N'DESERET SMALL LETTER OW' AS [Label], NCHAR(0xD801)+NCHAR(0xDC35) AS [Thing]
UNION ALL
SELECT N'DESERET CAPITAL LETTER OW' AS [Label], NCHAR(0xD801)+NCHAR(0xDC0D) AS [Thing]
UNION ALL
SELECT N'SmallButShouldBeCapital' AS [Label], UPPER(NCHAR(0xD801)+NCHAR(0xDC35)) AS [Thing]
Devoluciones (ampliada para que pueda ver el carácter suplementario):
Puede ver la lista completa (y actual) de caracteres en minúsculas y cambiar a mayúsculas usando la siguiente función de búsqueda en Unicode.org (puede ver los caracteres suplementarios desplazándose hacia abajo hasta llegar al "DESIERTO" sección, o simplemente presiona Control-Fy busca esa palabra):
http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AChanges_When_Titlecased%3DYes%3A%5D
Aunque, para ser sincero, este no es un gran beneficio, ya que es dudoso que alguien esté usando alguno de los Personajes suplementarios que pueden estar en mayúsculas. De cualquier manera, aquí está el código SQLCLR:
using System.Data.SqlTypes;
using System.Globalization;
using Microsoft.SqlServer.Server;
public class TitleCasing
{
[return: SqlFacet(MaxSize = 4000)]
[Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = true)]
public static SqlString TitleCase([SqlFacet(MaxSize = 4000)] SqlString InputString)
{
TextInfo _TxtInf = new CultureInfo(InputString.LCID).TextInfo;
return new SqlString (_TxtInf.ToTitleCase(InputString.Value));
}
}
Aquí está la sugerencia de @MikaelEriksson, modificada ligeramente para manejar NVARCHAR
datos y omitir palabras en mayúsculas (para que coincida más estrechamente con el comportamiento del método .NET), junto con una prueba de esa implementación T-SQL y de La implementación de SQLCLR:
SET NOCOUNT ON;
DECLARE @a NVARCHAR(50);
SET @a = N'qWeRtY kEyBoArD TEST<>&''"X one&TWO '
+ NCHAR(0xD801)+NCHAR(0xDC28)
+ N'pPLe '
+ NCHAR(0x24D0) -- ⓐ Circled "a"
+ NCHAR(0xFF24) -- D Full-width "D"
+ N'D u'
+ NCHAR(0x0308) -- ̈ (combining diaeresis / umlaut)
+ N'vU'
+ NCHAR(0x0308) -- ̈ (combining diaeresis / umlaut)
+ N'lA';
SELECT @a AS [Original];
SELECT STUFF((
SELECT N' '
+ IIF(UPPER(T3.V) <> T3.V COLLATE Latin1_General_100_BIN2,
UPPER(LEFT(T3.V COLLATE Latin1_General_100_CI_AS_SC, 1))
+ LOWER(STUFF(T3.V COLLATE Latin1_General_100_CI_AS_SC, 1, 1, N'')),
T3.V)
FROM (SELECT CAST(REPLACE((SELECT @a AS N'*' FOR XML PATH('')), N' ', N'<X/>')
AS XML).query('.')) AS T1(X)
CROSS APPLY T1.X.nodes('text()') AS T2(X)
CROSS APPLY (SELECT T2.X.value('.', 'NVARCHAR(70)')) AS T3(V)
FOR XML PATH(''), TYPE
).value('text()[1]', 'NVARCHAR(70)') COLLATE Latin1_General_100_CI_AS_SC, 1, 1, N'')
AS [Capitalize first letter only];
SELECT dbo.TitleCase(@a) AS [ToTitleCase];
Otra diferencia en el comportamiento es que esta implementación particular de T-SQL se divide solo en espacios, mientras que el ToTitleCase()
método considera que la mayoría de las no letras son separadores de palabras (de ahí la diferencia en el manejo de la parte "uno y DOS").
Ambas implementaciones manejan secuencias combinadas correctamente. Cada una de las letras acentuadas en "üvÜlA" se compone de una letra base y una diéresis / diéresis combinadas (los dos puntos sobre cada letra), y se convierten correctamente al otro caso en ambas pruebas.
Finalmente, una desventaja inesperada de la versión SQLCLR es que al realizar varias pruebas, encontré un error en el código .NET relacionado con su manejo de las letras en círculo (que ahora se ha informado en Microsoft Connect - ACTUALIZACIÓN: Connect ha sido se movió a /dev/null
, literalmente, por lo que es posible que deba volver a enviar esto si el problema persiste). La biblioteca .NET trata las letras en círculo como separadores de palabras, por lo que no convierte la "ⓐDD" en "Ⓐdd" como debería.
FYI
Una función SQLCLR pre-realizada que encapsula el TextInfo.ToTitleCase
método mencionado anteriormente ahora está disponible en la versión gratuita de SQL # (que escribí) como String_ToTitleCase y String_ToTitleCase4k .
😺