Конвертировать текст в PascalCase

Можно ли преобразовать текст из столбца таблицы в SQL Server в PascalCase только с помощью правильного кода SQL?

TABLE DEFINITION
----------------------
ID  int
CITTA   varchar(50)
PROV    varchar(50)
CAP varchar(50)
COD varchar(50)

Поле, содержащее текст для преобразования CITTA, Он содержит все значения в верхнем регистре, такие как "ABANO TERME", "ROMA" и так далее. Слова отделяются пробелом.

РЕДАКТИРОВАТЬ

Я забыл упомянуть, что некоторые слова имеют ударение ', Этот символ можно найти либо в конце слова, либо в середине.

РЕДАКТИРОВАТЬ 2:

Некоторые причуды, найденные по результатам:

  • Если у меня есть имя, подобное "ISOLA BALBA", это имя переводят в "IsolaBalba" (правильный регистр, но пропущено место)
  • Если у меня есть имя, подобное "ISOLA D'ASTI", оно преобразуется в "IsolaD'asti" (пропущенный пробел, как и раньше, и неправильный регистр. В этом случае правильный результат - "Isola D'Asti").

не могли бы вы дать мне несколько советов по этой маленькой проблеме?

3 ответа

Решение
DECLARE @T TABLE
(
ID  INT PRIMARY KEY,
CITTA   VARCHAR(50)
)
INSERT INTO @T
SELECT 1, 'ABANO TERME' UNION ALL SELECT 2, 'ROMA' UNION ALL SELECT 3, 'ISOLA D''ASTI';

IF OBJECT_ID('tempdb..#HolderTable') IS NOT NULL
    DROP TABLE #HolderTable

CREATE TABLE #HolderTable
(
Idx INT IDENTITY(1,1) PRIMARY KEY,
ID INT,
Word  VARCHAR(50)
)

CREATE NONCLUSTERED INDEX ix ON #HolderTable(ID)
;

WITH T1 AS
(
SELECT ID, CAST(N'<root><r>' + REPLACE(REPLACE(CITTA, '''', '''</r><r>'), ' ', ' </r><r>') + '</r></root>' AS XML) AS xl
FROM @T
)
INSERT INTO #HolderTable
SELECT ID, 
       r.value('.','NVARCHAR(MAX)') AS Item
 FROM T1
 CROSS APPLY
xl.nodes('//root/r') AS RECORDS(r)

SELECT 
      ID, 
      (SELECT STUFF(LOWER(Word),1,1,UPPER(LEFT(Word,1))) FROM #HolderTable WHERE [@T].ID =  #HolderTable.ID ORDER BY Idx FOR XML PATH('') )
FROM @T [@T]

Я рекомендую вам попробовать код, который я опубликовал в блоге некоторое время назад. Я подозреваю, что он будет соответствовать вашим требованиям очень хорошо, а также будет работать лучше, чем многие другие методы.

SQL Server правильная функция case

CREATE FUNCTION dbo.Proper(@DATA VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
  DECLARE @Position INT

  SELECT @DATA = STUFF(LOWER(@DATA), 1, 1, UPPER(LEFT(@DATA, 1))),
         @Position = PATINDEX('%[^a-zA-Z][a-z]%', @DATA COLLATE Latin1_General_Bin)

  WHILE @Position > 0
    SELECT @DATA = STUFF(@DATA, @Position, 2, UPPER(SUBSTRING(@DATA, @Position, 2))),
           @Position = PATINDEX('%[^a-zA-Z][a-z]%', @DATA COLLATE Latin1_General_Bin)

  RETURN @DATA
END

Эта функция немного быстрее, чем большинство, потому что она повторяется только один раз для каждого слова, которое требует заглавной буквы.

Попробуйте приведенную ниже функцию (отрегулируйте тип строки соответствующим образом). Только не используйте это в предложении WHERE - и рассмотрите последствия для производительности в другом месте. 12345678 - это просто какое-то произвольно большое значение, которое вы можете заменить на более подходящее!

CREATE FUNCTION dbo.ufn_PascalCase(@str AS VARCHAR(MAX)) RETURNS VARCHAR(MAX)
BEGIN
    SET @str = LOWER(@str)

    DECLARE @result VARCHAR(MAX) = ''

    DECLARE @spaceIndex INTEGER = CHARINDEX(' ', @str)
    WHILE @spaceIndex > 0
    BEGIN
        SET @result += UPPER(SUBSTRING(@str, 1, 1)) + SUBSTRING(@str, 2, @spaceIndex - 2)
        SET @str = SUBSTRING(@str, @spaceIndex + 1, 12345678)
        SET @spaceIndex = CHARINDEX(' ', @str)
    END

    SET @result += UPPER(SUBSTRING(@str, 1, 1)) + SUBSTRING(@str, 2, 12345678)

    RETURN @result
END

Что касается SQL 2017, это можно сделать довольно элегантно. В отличие от некоторых других ответов, это дает PascalCase, как и просили, а не правильный регистр. Он также работает для подчеркивания или пробелов (и нескольких знаков подряд).

CREATE OR ALTER FUNCTION dbo.fnPascalCase(@word NVARCHAR(MAX)) RETURNS NVARCHAR(MAX)
BEGIN
    DECLARE @t1 TABLE (Val NVARCHAR(MAX));
    INSERT INTO @t1 (Val)
    SELECT Val = UPPER(SUBSTRING(LTRIM(RTRIM(value)), 1, 1)) + LOWER(SUBSTRING(LTRIM(RTRIM(value)), 2, 2000000000)) FROM STRING_SPLIT(REPLACE(@word, ' ', '_'), '_')

    DECLARE @result NVARCHAR(MAX);

    SELECT @result = STRING_AGG(Val, '') FROM @t1
    RETURN @result
END

Применение:

SELECT dbo.fnPascalCase('taco___tuesday is   today') --Returns 'TacoTuesdayIsToday`
SELECT dbo.fnPascalCase('HELLO MY fRiEnD') --Returns 'HelloMyFriend`
Другие вопросы по тегам