SQL Server: переведите все ВЕРХНИЕ дела в надлежащие дела / заглавные дела - PullRequest
80 голосов
/ 23 октября 2008

У меня есть таблица, которая была импортирована как верхний регистр, и я хотел бы превратить ее в правильный регистр. Какой сценарий кто-нибудь из вас использовал для этого?

Ответы [ 19 ]

97 голосов
/ 23 октября 2008

Эта функция:

  • «Собственные случаи» все слова «ВЕРХНИЙ СЛУЧАЙ», разделенные пробелом
  • оставляет "строчные слова" в покое
  • работает правильно даже для неанглийских алфавитов
  • является переносимым в том смысле, что не использует необычные функции последних версий SQL-сервера
  • можно легко изменить, чтобы использовать NCHAR и NVARCHAR для поддержки юникода, а также любую длину параметра, которую вы считаете нужной
  • определение пустого пространства можно настроить
CREATE FUNCTION ToProperCase(@string VARCHAR(255)) RETURNS VARCHAR(255)
AS
BEGIN
  DECLARE @i INT           -- index
  DECLARE @l INT           -- input length
  DECLARE @c NCHAR(1)      -- current char
  DECLARE @f INT           -- first letter flag (1/0)
  DECLARE @o VARCHAR(255)  -- output string
  DECLARE @w VARCHAR(10)   -- characters considered as white space

  SET @w = '[' + CHAR(13) + CHAR(10) + CHAR(9) + CHAR(160) + ' ' + ']'
  SET @i = 1
  SET @l = LEN(@string)
  SET @f = 1
  SET @o = ''

  WHILE @i <= @l
  BEGIN
    SET @c = SUBSTRING(@string, @i, 1)
    IF @f = 1 
    BEGIN
     SET @o = @o + @c
     SET @f = 0
    END
    ELSE
    BEGIN
     SET @o = @o + LOWER(@c)
    END

    IF @c LIKE @w SET @f = 1

    SET @i = @i + 1
  END

  RETURN @o
END

Результат:

dbo.ToProperCase('ALL UPPER CASE and    SOME lower ÄÄ ÖÖ ÜÜ ÉÉ ØØ ĈĈ ÆÆ')
-----------------------------------------------------------------
All Upper Case and      Some lower Ää Öö Üü Éé Øø Cc Ææ
69 голосов
/ 23 октября 2008

Вот UDF, который сделает свое дело ...

create function ProperCase(@Text as varchar(8000))
returns varchar(8000)
as
begin
  declare @Reset bit;
  declare @Ret varchar(8000);
  declare @i int;
  declare @c char(1);

  if @Text is null
    return null;

  select @Reset = 1, @i = 1, @Ret = '';

  while (@i <= len(@Text))
    select @c = substring(@Text, @i, 1),
      @Ret = @Ret + case when @Reset = 1 then UPPER(@c) else LOWER(@c) end,
      @Reset = case when @c like '[a-zA-Z]' then 0 else 1 end,
      @i = @i + 1
  return @Ret
end

Вам все равно придется использовать его для обновления ваших данных.

35 голосов
/ 18 декабря 2013
UPDATE titles
  SET title =
      UPPER(LEFT(title, 1)) +
        LOWER(RIGHT(title, LEN(title) - 1))

http://sqlmag.com/t-sql/how-title-case-column-value

17 голосов
/ 24 октября 2008

Если вы можете включить CLR в SQL Server (требуется 2005 или более поздняя версия), тогда вы можете создать функцию CLR , которая использует встроенную функцию TextInfo.ToTitleCase , которая позволит вам нужно создать культурный способ сделать это всего за несколько строк кода.

7 голосов
/ 29 июля 2016

Я немного опоздал в игре, но считаю, что она более функциональна и работает с любым языком, включая русский, немецкий, тайский, вьетнамский и т. Д. Это сделает заглавными буквами что-нибудь после 'или - или. или (или) или пробел (очевидно:).

CREATE FUNCTION [dbo].[fnToProperCase]( @name nvarchar(500) )
RETURNS nvarchar(500)
AS
BEGIN
declare @pos    int = 1
      , @pos2   int

if (@name <> '')--or @name = lower(@name) collate SQL_Latin1_General_CP1_CS_AS or @name = upper(@name) collate SQL_Latin1_General_CP1_CS_AS)
begin
    set @name = lower(rtrim(@name))
    while (1 = 1)
    begin
        set @name = stuff(@name, @pos, 1, upper(substring(@name, @pos, 1)))
        set @pos2 = patindex('%[- ''.)(]%', substring(@name, @pos, 500))
        set @pos += @pos2
        if (isnull(@pos2, 0) = 0 or @pos > len(@name))
            break
    end
end

return @name
END
GO
7 голосов
/ 25 февраля 2015

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

CREATE FUNCTION [dbo].[fnConvert_TitleCase] (@InputString VARCHAR(4000) )
RETURNS VARCHAR(4000)
AS
BEGIN
DECLARE @Index INT
DECLARE @Char CHAR(1)
DECLARE @OutputString VARCHAR(255)

SET @OutputString = LOWER(@InputString)
SET @Index = 2
SET @OutputString = STUFF(@OutputString, 1, 1,UPPER(SUBSTRING(@InputString,1,1)))

WHILE @Index <= LEN(@InputString)
BEGIN
    SET @Char = SUBSTRING(@InputString, @Index, 1)
    IF @Char IN (' ', ';', ':', '!', '?', ',', '.', '_', '-', '/', '&','''','(')
    IF @Index + 1 <= LEN(@InputString)
BEGIN
    IF @Char != ''''
    OR
    UPPER(SUBSTRING(@InputString, @Index + 1, 1)) != 'S'
    SET @OutputString =
    STUFF(@OutputString, @Index + 1, 1,UPPER(SUBSTRING(@InputString, @Index + 1, 1)))
END
    SET @Index = @Index + 1
END

RETURN ISNULL(@OutputString,'')
END

Тестовые звонки:

select dbo.fnConvert_TitleCase(Upper('ÄÄ ÖÖ ÜÜ ÉÉ ØØ ĈĈ ÆÆ')) as test
select dbo.fnConvert_TitleCase(upper('Whatever the mind of man can conceive and believe, it can achieve. – Napoleon hill')) as test

Результаты:

enter image description here

3 голосов
/ 02 июля 2015

Если вы в SSIS импортируете данные со смешанным регистром и вам нужно выполнить поиск по столбцу с соответствующим регистром, вы заметите, что поиск не удастся, когда источник смешан и источник поиска правильный. Вы также заметите, что не можете использовать правую и левую функции SSIS для SQL Server 2008r2 для производных столбцов. Вот решение, которое работает для меня:

UPPER(substring(input_column_name,1,1)) + LOWER(substring(input_column_name, 2, len(input_column_name)-1))
1 голос
/ 07 июля 2011

Имеет смысл сохранить поиск исключений, чтобы позаботиться о фон Неймана, Маккейна, ДеГузмана и Джонсона-Смита.

1 голос
/ 19 ноября 2009

Вот версия, которая использует таблицу последовательности или чисел, а не цикл. Вы можете изменить предложение WHERE, чтобы оно соответствовало вашим личным правилам, когда нужно преобразовывать символ в верхний регистр. Я только что включил простой набор, который будет заглавными буквами любой буквы, за которой следует не буква, за исключением апострофов. Это означает, что 123apple будет иметь совпадение на «a», потому что «3» не является буквой. Если вам нужен только пробел (пробел, табуляция, возврат каретки, перевод строки), вы можете заменить шаблон '[^a-z]' на '[' + Char(32) + Char(9) + Char(13) + Char(10) + ']'.


CREATE FUNCTION String.InitCap( @string nvarchar(4000) ) RETURNS nvarchar(4000) AS
BEGIN

-- 1. Convert all letters to lower case
    DECLARE @InitCap nvarchar(4000); SET @InitCap = Lower(@string);

-- 2. Using a Sequence, replace the letters that should be upper case with their upper case version
    SELECT @InitCap = Stuff( @InitCap, n, 1, Upper( SubString( @InitCap, n, 1 ) ) )
    FROM (
        SELECT (1 + n1.n + n10.n + n100.n + n1000.n) AS n
        FROM       (SELECT 0 AS n UNION SELECT    1 UNION SELECT    2 UNION SELECT    3 UNION SELECT    4 UNION SELECT    5 UNION SELECT    6 UNION SELECT    7 UNION SELECT    8 UNION SELECT    9) AS    n1
        CROSS JOIN (SELECT 0 AS n UNION SELECT   10 UNION SELECT   20 UNION SELECT   30 UNION SELECT   40 UNION SELECT   50 UNION SELECT   60 UNION SELECT   70 UNION SELECT   80 UNION SELECT   90) AS   n10
        CROSS JOIN (SELECT 0 AS n UNION SELECT  100 UNION SELECT  200 UNION SELECT  300 UNION SELECT  400 UNION SELECT  500 UNION SELECT  600 UNION SELECT  700 UNION SELECT  800 UNION SELECT  900) AS  n100
        CROSS JOIN (SELECT 0 AS n UNION SELECT 1000 UNION SELECT 2000 UNION SELECT 3000)                                                                                                             AS n1000
        ) AS Sequence
    WHERE 
        n BETWEEN 1 AND Len( @InitCap )
    AND SubString( @InitCap, n, 1 ) LIKE '[a-z]'                 /* this character is a letter */
    AND (
        n = 1                                                    /* this character is the first `character` */
        OR SubString( @InitCap, n-1, 1 ) LIKE '[^a-z]'           /* the previous character is NOT a letter */
        )
    AND (
        n < 3                                                    /* only test the 3rd or greater characters for this exception */
        OR SubString( @InitCap, n-2, 3 ) NOT LIKE '[a-z]''[a-z]' /* exception: The pattern <letter>'<letter> should not capatolize the letter following the apostrophy */
        )

-- 3. Return the modified version of the input
    RETURN @InitCap

END
1 голос
/ 24 октября 2008

Ссылка, которую я разместил выше, является отличным вариантом, который решает основную проблему: мы никогда не можем программно учесть все случаи (Смит-Джонс, фон Хауссен, Джон Смит М.Д.), по крайней мере, элегантным способом. Тони вводит концепцию символа исключения / прерывания, чтобы иметь дело с этими случаями. В любом случае, основываясь на идее Черво (верхние все нижние символы предшествуют пробелом), операторы замены могут быть помещены в одну замену на основе таблицы. В самом деле, любая комбинация символов «низкий / повышенный» может быть вставлена ​​в @alpha, и оператор не изменится:

declare @str    nvarchar(8000)
declare @alpha  table (low nchar(1), up nchar(1))


set @str = 'ALL UPPER CASE and    SOME lower ÄÄ ÖÖ ÜÜ ÉÉ ØØ ĈĈ ÆÆ'

-- stage the alpha (needs number table)
insert into @alpha
    -- A-Z / a-z
    select      nchar(n+32),
                nchar(n)
    from        dbo.Number
    where       n between 65 and 90 or
                n between 192 and 223

-- append space at start of str
set @str = lower(' ' + @str)

-- upper all lower case chars preceded by space
select  @str = replace(@str, ' ' + low, ' ' + up) 
from    @Alpha

select @str
...