Інший варіант - це впоратися з допомогою SQLCLR. Існує навіть метод, доступний в .NET, який робить це: TextInfo.ToTitleCase (в System.Globalization
). Цей метод дозволить виділити великі регістри першої літери кожного слова, а малі регістри - інші літери. На відміну від інших пропозицій тут, він також пропускає слова, які є у великому регістрі, вважаючи, що вони є абревіатурами. Звичайно, якщо така поведінка бажана, було б досить легко оновити будь-яку з пропозицій T-SQL, щоб зробити це також.
Одна з переваг методу .NET полягає в тому, що він може вводити великі літери, які є додатковими символами. Наприклад: DESERET SMALL LETTER OW має відображення великого регістру DESERET CAPITAL LETTER OW (обидва відображаються як поля, коли я вставляю їх сюди) , але UPPER()
функція не змінює малу версію на верхню, навіть коли для поточної бази даних встановлено стандартне зіставлення Latin1_General_100_CI_AS_SC
. Це здається узгодженим з документацією MSDN, яка не містить переліку UPPER
та LOWER
у графіку функцій, які поводяться по-різному при використанні _SC
Collation: Collation і Unicode Support: Додаткові символи .
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]
Повернення (збільшене, щоб ви могли бачити додатковий символ):
Ви можете побачити повний (і поточний) список символів з малих літер і змінити їх на великі регістри, скориставшись такою функцією пошуку на Unicode.org (Ви можете переглянути додаткові символи, прокручуючи вниз, доки не перейдете до "DESERET" розділ або просто натисніть Control-Fі знайдіть це слово):
http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AChanges_When_Titlecased%3DYes%3A%5D
Хоча, чесно кажучи, це не є величезною перевагою, оскільки сумнівно, що хтось насправді використовує будь-який із додаткових символів, який може бути визначений назви. У будь-якому випадку, ось код 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));
}
}
Ось пропозиція @ MikaelEriksson - трохи модифікована для обробки NVARCHAR
даних, а також пропуску слів, які є великими літерами (щоб більш точно відповідати поведінці методу .NET) - разом з тестом на те, що реалізація T-SQL і реалізація 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];
Інша відмінність поведінки полягає в тому, що саме ця реалізація T-SQL розбивається на лише пробіли, тоді як ToTitleCase()
метод вважає більшість не букв роздільником слів (звідси різниця в обробці частини "one & TWO").
Обидві реалізації правильно обробляють поєднання послідовностей. Кожна з букв із наголосом у "üvÜlA" складається з базової літери та поєднувального діарезу / умулату (дві крапки над кожною буквою), і вони правильно перетворені в інший випадок в обох тестах.
Нарешті, одним несподіваним недоліком версії SQLCLR є те, що, придумуючи різні тести, я виявив помилку в коді .NET, пов’язаний з його обробкою круглими літерами (про що зараз повідомлялося на Microsoft Connect - UPDATE: Connect було перейшов до /dev/null
- буквально - тому мені може знадобитися повторно надіслати це, якщо проблема все ще існує). Бібліотека .NET розглядає циркульовані букви як роздільники слів, тому не перетворює "ⓐDD" на "Ⓐdd" як слід.
FYI
Попередньо виконана функція SQLCLR, інкапсуляція TextInfo.ToTitleCase
вищезгаданого методу, тепер доступна у безкоштовній версії SQL # (про яку я писав) як String_ToTitleCase та String_ToTitleCase4k .
😺