У мене є таблиця, яка була імпортована як ВЕРХНЯ СПРАВА, і я хотів би перетворити її на належну справу. Яким сценарієм хтось із вас скористався цим?
У мене є таблиця, яка була імпортована як ВЕРХНЯ СПРАВА, і я хотів би перетворити її на належну справу. Яким сценарієм хтось із вас скористався цим?
Відповіді:
Ось СДС, який зробить трюк ...
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
Вам все одно доведеться використовувати його для оновлення даних.
Ця функція:
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 Ææ
O'DONNELL
не змінювалося на O'donnell
.
SET @o = @o + @c
до SET @o = @o + UPPER(@c)
. =)
UPDATE titles
SET title =
UPPER(LEFT(title, 1)) +
LOWER(RIGHT(title, LEN(title) - 1))
title
пусте.
WHERE title IS NOT NULL
до кінця, щоб вирішити проблему @Serg.
SUBSTRING
замістьRIGHT
Якщо ви можете ввімкнути CLR у SQL Server (потрібна версія 2005 або пізнішої версії), ви можете створити функцію CLR, яка використовує вбудовану функцію TextInfo.ToTitleCase, яка дозволить вам створити культурний спосіб зробити це лише за декілька рядки коду.
Я знаю, що це пізній пост у цій темі, але, варто подивитися. Ця функція працює для мене завжди. Тож думав поділитися цим.
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
Результати:
Я трохи запізнююся в грі, але я вважаю, що це більш функціонально, і вона працює з будь-якою мовою, включаючи російську, німецьку, тайську, в'єтнамську і т.д. або (або) або пробіл (очевидно :).
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
Якщо ви перебуваєте в імпорті даних SSIS, у яких змішані обстановки, і вам потрібно здійснити пошук у стовпці з належним регістром, ви помітите, що пошук не працює там, де джерело змішується та джерело пошуку є належним. Ви також помітите, що не можна використовувати праву та ліву функції - це SSIS для SQL Server 2008r2 для похідних стовпців. Ось рішення, яке мені підходить:
UPPER(substring(input_column_name,1,1)) + LOWER(substring(input_column_name, 2, len(input_column_name)-1))
Ось версія, яка використовує таблицю послідовностей або чисел, а не цикл. Ви можете змінити речення WHERE, щоб відповідати вашим особистим правилам щодо перетворення символу у верхній регістр. Я щойно включив простий набір, який буде писати великі літери на будь-які літери, що переходять небуквеними, за винятком апострофів. Це означає, що коли-небудь означає, що 123apple матиме збіг на "а", оскільки "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
Посилання, яке я розмістив вище, є чудовим варіантом, який вирішує головну проблему: ми ніколи не можемо програмно враховувати всі випадки (Сміт-Джонс, фон Хауссен, Джон Сміт, доктор медичних наук), принаймні не елегантно. Тоні вводить поняття винятку / зламаного персонажа для вирішення цих випадків. У будь-якому випадку, спираючись на ідею Черво (верхні всі нижні символи, перед якими стоїть пробіл), замість цього оператори replace можуть бути заміщені в одну таблицю на основі заміни. Дійсно, будь-яка комбінація символів з низьким та вгору значенням може бути вставлена в @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
Відповідь @Richard Sayakanit запозичив та вдосконалив. Це обробляє кілька слів. Як і його відповідь, тут не використовуються UDF, лише вбудовані функції ( STRING_SPLIT
і STRING_AGG
), і це досить швидко. STRING_AGG
потрібен SQL Server 2017, але ви завжди можете скористатися STUFF/XML
фокусом. Не впорається з кожним винятком, але може чудово працювати для багатьох вимог.
SELECT StateName = 'North Carolina'
INTO #States
UNION ALL
SELECT 'Texas'
;WITH cteData AS
(
SELECT
UPPER(LEFT(value, 1)) +
LOWER(RIGHT(value, LEN(value) - 1)) value, op.StateName
FROM #States op
CROSS APPLY STRING_SPLIT(op.StateName, ' ') AS ss
)
SELECT
STRING_AGG(value, ' ')
FROM cteData c
GROUP BY StateName
Невелика модифікація відповіді @ Галвезької - яка перетворюється, наприклад, St Elizabeth's
у St Elizabeth'S
.
Ця модифікація зберігає апострофи як малі регістри, де s в кінці рядка, що надається, або s після пробілу (і лише за таких обставин).
create function properCase(@text as varchar(8000))
returns varchar(8000)
as
begin
declare @reset int;
declare @ret varchar(8000);
declare @i int;
declare @c char(1);
declare @d char(1);
if @text is null
return null;
select @reset = 1, @i = 1, @ret = '';
while (@i <= len(@text))
select
@c = substring(@text, @i, 1),
@d = substring(@text, @i+1, 1),
@ret = @ret + case when @reset = 1 or (@reset=-1 and @c!='s') or (@reset=-1 and @c='s' and @d!=' ') then upper(@c) else lower(@c) end,
@reset = case when @c like '[a-za-z]' then 0 when @c='''' then -1 else 1 end,
@i = @i + 1
return @ret
end
Виходить:
st elizabeth's
в St Elizabeth's
o'keefe
в O'Keefe
o'sullivan
в O'Sullivan
Зауваження інших, що різні варіанти є кращими для введення не англійською мовою, залишаються такими.
Я думаю, ви виявите, що наступне є більш ефективним:
IF OBJECT_ID('dbo.ProperCase') IS NOT NULL
DROP FUNCTION dbo.ProperCase
GO
CREATE FUNCTION dbo.PROPERCASE (
@str VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
SET @str = ' ' + @str
SET @str = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @str, ' a', ' A'), ' b', ' B'), ' c', ' C'), ' d', ' D'), ' e', ' E'), ' f', ' F'), ' g', ' G'), ' h', ' H'), ' i', ' I'), ' j', ' J'), ' k', ' K'), ' l', ' L'), ' m', ' M'), ' n', ' N'), ' o', ' O'), ' p', ' P'), ' q', ' Q'), ' r', ' R'), ' s', ' S'), ' t', ' T'), ' u', ' U'), ' v', ' V'), ' w', ' W'), ' x', ' X'), ' y', ' Y'), ' z', ' Z')
RETURN RIGHT(@str, LEN(@str) - 1)
END
GO
Оператор replace можна вирізати та вставити безпосередньо в запит SQL. Це дуже некрасиво, проте, замінивши @str на потрібний вам стовпець, ви не заплатите ціну за неявний курсор, як ви будете за розміщений таким чином udfs. Я вважаю, що навіть використання мого UDF набагато ефективніше.
О, і замість того, щоб генерувати оператор replace вручну, використовуйте це:
-- Code Generator for expression
DECLARE @x INT,
@c CHAR(1),
@sql VARCHAR(8000)
SET @x = 0
SET @sql = '@str' -- actual variable/column you want to replace
WHILE @x < 26
BEGIN
SET @c = CHAR(ASCII('a') + @x)
SET @sql = 'REPLACE(' + @sql + ', '' ' + @c+ ''', '' ' + UPPER(@c) + ''')'
SET @x = @x + 1
END
PRINT @sql
У будь-якому випадку це залежить від кількості рядків. Я хотів би, щоб ти міг просто зробити s / \ b ([az]) / uc $ 1 /, але ну ми добре працюємо з наявними у нас інструментами.
ПРИМІТКА - вам потрібно було б використовувати це, як це було б потрібно використовувати як .... SELECT dbo.ProperCase (LOWER (стовпець)), оскільки стовпець у верхньому регістрі. Це фактично працює досить швидко на моєму столі з 5000 записів (навіть не на одну секунду) навіть з нижньою.
У відповідь на безліч коментарів щодо інтернаціоналізації я представляю наступну реалізацію, яка обробляє кожен символ ascii, покладаючись лише на реалізацію SQL Server верхнього та нижнього рівня. Пам’ятайте, ми використовуємо тут змінні VARCHAR, що означає, що вони можуть містити лише значення ASCII. Для того, щоб використовувати подальші міжнародні алфавіти, вам слід використовувати NVARCHAR. Логіка була б схожою, але вам потрібно було б використовувати UNICODE та NCHAR замість ASCII І CHAR, а оператор replace був би набагато величезнішим ....
-- Code Generator for expression
DECLARE @x INT,
@c CHAR(1),
@sql VARCHAR(8000),
@count INT
SEt @x = 0
SET @count = 0
SET @sql = '@str' -- actual variable you want to replace
WHILE @x < 256
BEGIN
SET @c = CHAR(@x)
-- Only generate replacement expression for characters where upper and lowercase differ
IF @x = ASCII(LOWER(@c)) AND @x != ASCII(UPPER(@c))
BEGIN
SET @sql = 'REPLACE(' + @sql + ', '' ' + @c+ ''', '' ' + UPPER(@c) + ''')'
SET @count = @count + 1
END
SET @x = @x + 1
END
PRINT @sql
PRINT 'Total characters substituted: ' + CONVERT(VARCHAR(255), @count)
В основному передумовою мого методу є торгівля попередніми обчисленнями для підвищення ефективності. Повна реалізація ASCII така:
IF OBJECT_ID('dbo.ProperCase') IS NOT NULL
DROP FUNCTION dbo.ProperCase
GO
CREATE FUNCTION dbo.PROPERCASE (
@str VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
SET @str = ' ' + @str
SET @str = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@str, ' a', ' A'), ' b', ' B'), ' c', ' C'), ' d', ' D'), ' e', ' E'), ' f', ' F'), ' g', ' G'), ' h', ' H'), ' i', ' I'), ' j', ' J'), ' k', ' K'), ' l', ' L'), ' m', ' M'), ' n', ' N'), ' o', ' O'), ' p', ' P'), ' q', ' Q'), ' r', ' R'), ' s', ' S'), ' t', ' T'), ' u', ' U'), ' v', ' V'), ' w', ' W'), ' x', ' X'), ' y', ' Y'), ' z', ' Z'), ' š', ' Š'), ' œ', ' Œ'), ' ž', ' Ž'), ' à', ' À'), ' á', ' Á'), ' â', ' Â'), ' ã', ' Ã'), ' ä', ' Ä'), ' å', ' Å'), ' æ', ' Æ'), ' ç', ' Ç'), ' è', ' È'), ' é', ' É'), ' ê', ' Ê'), ' ë', ' Ë'), ' ì', ' Ì'), ' í', ' Í'), ' î', ' Î'), ' ï', ' Ï'), ' ð', ' Ð'), ' ñ', ' Ñ'), ' ò', ' Ò'), ' ó', ' Ó'), ' ô', ' Ô'), ' õ', ' Õ'), ' ö', ' Ö'), ' ø', ' Ø'), ' ù', ' Ù'), ' ú', ' Ú'), ' û', ' Û'), ' ü', ' Ü'), ' ý', ' Ý'), ' þ', ' Þ'), ' ÿ', ' Ÿ')
RETURN RIGHT(@str, LEN(@str) - 1)
END
GO
Чи не пізно повертатися назад і отримувати великі дані?
Результати вашої обробки можуть не сподобатися фондам Неймана, Маккейна, ДеГузмана та Джонсона-Сміта вашої клієнтської бази ...
Також я здогадуюсь, що це призначене для одноразового оновлення даних? Можливо, буде простіше експортувати, фільтрувати / модифікувати та повторно імпортувати виправлені імена в базу даних, і тоді ви можете використовувати підходи, що не пов'язані з SQL, для виправлення імен ...
Ось ще один варіант, який я знайшов на форумах SQLTeam.com @ http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=47718
create FUNCTION PROPERCASE
(
--The string to be converted to proper case
@input varchar(8000)
)
--This function returns the proper case string of varchar type
RETURNS varchar(8000)
AS
BEGIN
IF @input IS NULL
BEGIN
--Just return NULL if input string is NULL
RETURN NULL
END
--Character variable declarations
DECLARE @output varchar(8000)
--Integer variable declarations
DECLARE @ctr int, @len int, @found_at int
--Constant declarations
DECLARE @LOWER_CASE_a int, @LOWER_CASE_z int, @Delimiter char(3), @UPPER_CASE_A int, @UPPER_CASE_Z int
--Variable/Constant initializations
SET @ctr = 1
SET @len = LEN(@input)
SET @output = ''
SET @LOWER_CASE_a = 97
SET @LOWER_CASE_z = 122
SET @Delimiter = ' ,-'
SET @UPPER_CASE_A = 65
SET @UPPER_CASE_Z = 90
WHILE @ctr <= @len
BEGIN
--This loop will take care of reccuring white spaces
WHILE CHARINDEX(SUBSTRING(@input,@ctr,1), @Delimiter) > 0
BEGIN
SET @output = @output + SUBSTRING(@input,@ctr,1)
SET @ctr = @ctr + 1
END
IF ASCII(SUBSTRING(@input,@ctr,1)) BETWEEN @LOWER_CASE_a AND @LOWER_CASE_z
BEGIN
--Converting the first character to upper case
SET @output = @output + UPPER(SUBSTRING(@input,@ctr,1))
END
ELSE
BEGIN
SET @output = @output + SUBSTRING(@input,@ctr,1)
END
SET @ctr = @ctr + 1
WHILE CHARINDEX(SUBSTRING(@input,@ctr,1), @Delimiter) = 0 AND (@ctr <= @len)
BEGIN
IF ASCII(SUBSTRING(@input,@ctr,1)) BETWEEN @UPPER_CASE_A AND @UPPER_CASE_Z
BEGIN
SET @output = @output + LOWER(SUBSTRING(@input,@ctr,1))
END
ELSE
BEGIN
SET @output = @output + SUBSTRING(@input,@ctr,1)
END
SET @ctr = @ctr + 1
END
END
RETURN @output
END
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
Я знаю, що диявол у деталях (особливо там, де це стосується персональних даних людей), і що було б дуже приємно мати правильно написані великі імена, але вищезазначений тип клопоту - це те, чому прагматичні, уважні серед нас люди використовують наступне :
SELECT UPPER('Put YoUR O'So oddLy casED McWeird-nAme von rightHERE here')
З мого досвіду, люди прекрасно бачать ЇХНЕ ІМ'Я ... навіть тоді, коли це вже половина речення.
Посилання: росіяни використовували олівець!
Це працювало в SSMS:
Select Jobtitle,
concat(Upper(LEFT(jobtitle,1)), SUBSTRING(jobtitle,2,LEN(jobtitle))) as Propercase
From [HumanResources].[Employee]
Якщо ви знаєте, що всі дані - це лише одне слово, ось рішення. Спочатку оновіть стовпець до нижчого рівня, а потім виконайте наступне
update tableName set columnName =
upper(SUBSTRING(columnName, 1, 1)) + substring(columnName, 2, len(columnName)) from tableName
Нещодавно довелося боротися з цим, і придумав наступне після того, як нічого не вдарило все, що я хотів. Це дозволить скласти ціле речення, випадки для спеціального оброблення слів. У нас також виникли проблеми зі словами "одного слова", з якими справляється багато простих методів, але не більш складні методи. Змінна одного повернення, без циклів або курсорів.
CREATE FUNCTION ProperCase(@Text AS NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS BEGIN
DECLARE @return NVARCHAR(MAX)
SELECT @return = COALESCE(@return + ' ', '') + Word FROM (
SELECT CASE
WHEN LOWER(value) = 'llc' THEN UPPER(value)
WHEN LOWER(value) = 'lp' THEN UPPER(value) --Add as many new special cases as needed
ELSE
CASE WHEN LEN(value) = 1
THEN UPPER(value)
ELSE UPPER(LEFT(value, 1)) + (LOWER(RIGHT(value, LEN(value) - 1)))
END
END AS Word
FROM STRING_SPLIT(@Text, ' ')
) tmp
RETURN @return
END
Скопіюйте та вставте свої дані у MS Word і використовуйте вбудований текст-перетворення для "Використання великих літер у кожному слові". Порівняйте з вихідними даними, щоб вирішити винятки. Я не бачу жодного способу обходу винятків типу "MacDonald" та "IBM" вручну, але так я це зробив FWIW.