Convert excel data into SQL table - sql

I have a excel which is having some columns (lets say column1, column2, column3, ....so on) and rows, here number of columns and rows are not fixed.
Now data from this excel is copied and inserted into one column (type - nvarchar(max)) of some table...now i have to take data from this column and need to show in tabular format in SQL.
If number of columns had been fixed, i can easily convert column value in xml and show data in tabular format. As number of columns are not fixed, please suggest, how to get desired output.

below is my assumption,
1. you use ',' as delimiter.
2. you not concern about the performance since you insert everything in one column
Will the below helps?
/*create table
CREATE TABLE Tbl ( col nvarchar(max))
insert into Tbl values ('1,2,3,4'),('1,2,3'),('1,2')
***/
DECLARE #maxcol as int,#i as int
SELECT #maxcol=max(LEN(col) - LEN(REPLACE(col, ',', '')))+1 FROM Tbl
select #i=1
declare #nvarsql as nvarchar(max)
select #nvarsql =''
while #i<=#maxcol
begin
set #nvarsql = #nvarsql + ' ISNULL(DBO.fnString_DelimeterIndex(col,'','',' + cast(#i as varchar) +' ),'''') as COL' + CAST(#i AS VARCHAR) + ','
set #i = #i +1
end
if #nvarsql <>''
begin
set #nvarsql = 'SELECT ' + left(#nvarsql,LEN(#nvarsql)-1) + ' FROM Tbl'
end
PRINT #nvarsql
EXEC (#nvarsql)
the Scalar function download from somewhere
ALTER FUNCTION [dbo].[fnString_DelimeterIndex]
(
#Text NVARCHAR(4000),
#Delimiter CHAR,
#Section SMALLINT
)
RETURNS NVARCHAR(4000)
AS
BEGIN
DECLARE #NextPos SMALLINT,
#LastPos SMALLINT,
#Found SMALLINT,
#REVERSE BIT
IF #Section < 0
SELECT #Text = REVERSE(#Text)--, #Section=1,#REVERSE=1
SELECT #NextPos = CHARINDEX(#Delimiter, #Text, 1),
#LastPos = 0,
#Found = 1
WHILE #NextPos > 0 AND ABS(#Section) <> #Found
SELECT #LastPos = #NextPos,
#NextPos = CHARINDEX(#Delimiter, #Text, #NextPos + 1),
#Found = #Found + 1
RETURN CASE
WHEN #Found <> ABS(#Section) OR #Section = 0 THEN NULL
--WHEN #REVERSE =1 THEN
WHEN #Section > 0 THEN SUBSTRING(#Text, #LastPos + 1, CASE WHEN #NextPos = 0 THEN DATALENGTH(#Text) - #LastPos ELSE #NextPos - #LastPos - 1 END)
ELSE REVERSE(SUBSTRING(#Text, #LastPos + 1, CASE WHEN #NextPos = 0 THEN DATALENGTH(#Text) - #LastPos ELSE #NextPos - #LastPos - 1 END))
END
END
results from above sample
COL1 COL2 COL3 COL4
1 2 3 4
1 2 3
1 2

Related

SQL Server capitalize every first letter of every word with loop [duplicate]

What’s the best way to capitalize the first letter of each word in a string in SQL Server.
From http://www.sql-server-helper.com/functions/initcap.aspx
CREATE FUNCTION [dbo].[InitCap] ( #InputString varchar(4000) )
RETURNS VARCHAR(4000)
AS
BEGIN
DECLARE #Index INT
DECLARE #Char CHAR(1)
DECLARE #PrevChar CHAR(1)
DECLARE #OutputString VARCHAR(255)
SET #OutputString = LOWER(#InputString)
SET #Index = 1
WHILE #Index <= LEN(#InputString)
BEGIN
SET #Char = SUBSTRING(#InputString, #Index, 1)
SET #PrevChar = CASE WHEN #Index = 1 THEN ' '
ELSE SUBSTRING(#InputString, #Index - 1, 1)
END
IF #PrevChar IN (' ', ';', ':', '!', '?', ',', '.', '_', '-', '/', '&', '''', '(')
BEGIN
IF #PrevChar != '''' OR UPPER(#Char) != 'S'
SET #OutputString = STUFF(#OutputString, #Index, 1, UPPER(#Char))
END
SET #Index = #Index + 1
END
RETURN #OutputString
END
GO
There is a simpler/smaller one here (but doesn't work if any row doesn't have spaces, "Invalid length parameter passed to the RIGHT function."):
http://www.devx.com/tips/Tip/17608
As a table-valued function:
CREATE FUNCTION dbo.InitCap(#v AS VARCHAR(MAX))
RETURNS TABLE
AS
RETURN
WITH a AS (
SELECT (
SELECT UPPER(LEFT(value, 1)) + LOWER(SUBSTRING(value, 2, LEN(value))) AS 'data()'
FROM string_split(#v, ' ')
ORDER BY CHARINDEX(value,#v)
FOR XML PATH (''), TYPE) ret)
SELECT CAST(a.ret AS varchar(MAX)) ret from a
GO
Note that string_split requires COMPATIBILITY_LEVEL 130.
A variation of the one I've been using for quite some time is:
CREATE FUNCTION [widget].[properCase](#string varchar(8000)) RETURNS varchar(8000) AS
BEGIN
SET #string = LOWER(#string)
DECLARE #i INT
SET #i = ASCII('a')
WHILE #i <= ASCII('z')
BEGIN
SET #string = REPLACE( #string, ' ' + CHAR(#i), ' ' + CHAR(#i-32))
SET #i = #i + 1
END
SET #string = CHAR(ASCII(LEFT(#string, 1))-32) + RIGHT(#string, LEN(#string)-1)
RETURN #string
END
You can easily modify to handle characters after items other than spaces if you wanted to.
Another solution without using the loop - pure set-based approach with recursive CTE
create function [dbo].InitCap (#value varchar(max))
returns varchar(max) as
begin
declare
#separator char(1) = ' ',
#result varchar(max) = '';
with r as (
select value, cast(null as varchar(max)) [x], cast('' as varchar(max)) [char], 0 [no] from (select rtrim(cast(#value as varchar(max))) [value]) as j
union all
select right(value, len(value)-case charindex(#separator, value) when 0 then len(value) else charindex(#separator, value) end) [value]
, left(r.[value], case charindex(#separator, r.value) when 0 then len(r.value) else abs(charindex(#separator, r.[value])-1) end ) [x]
, left(r.[value], 1)
, [no] + 1 [no]
from r where value > '')
select #result = #result +
case
when ascii([char]) between 97 and 122
then stuff(x, 1, 1, char(ascii([char])-32))
else x
end + #separator
from r where x is not null;
set #result = rtrim(#result);
return #result;
end
If you are looking for the answer to the same question in Oracle/PLSQL then you may use the function INITCAP. Below is an example for the attribute dname from a table department which has the values ('sales', 'management', 'production', 'development').
SQL> select INITCAP(dname) from department;
INITCAP(DNAME)
--------------------------------------------------
Sales
Management
Production
Development
;WITH StudentList(Name) AS (
SELECT CONVERT(varchar(50), 'Carl-VAN')
UNION SELECT 'Dean o''brian'
UNION SELECT 'Andrew-le-Smith'
UNION SELECT 'Eddy thompson'
UNION SELECT 'BOBs-your-Uncle'
), Student AS (
SELECT CONVERT(varchar(50), UPPER(LEFT(Name, 1)) + LOWER(SUBSTRING(Name, 2, LEN(Name)))) Name,
pos = PATINDEX('%[-'' ]%', Name)
FROM StudentList
UNION ALL
SELECT CONVERT(varchar(50), LEFT(Name, pos) + UPPER(SUBSTRING(Name, pos + 1, 1)) + SUBSTRING(Name, pos + 2, LEN(Name))) Name,
pos = CASE WHEN PATINDEX('%[-'' ]%', RIGHT(Name, LEN(Name) - pos)) = 0 THEN 0 ELSE pos + PATINDEX('%[-'' ]%', RIGHT(Name, LEN(Name) - pos)) END
FROM Student
WHERE pos > 0
)
SELECT Name
FROM Student
WHERE pos = 0
ORDER BY Name
This will result in:
Andrew-Le-Smith
Bobs-Your-Uncle
Carl-Van
Dean O'Brian
Eddy Thompson
Using a recursive CTE set based query should out perform a procedural while loop query.
Here I also have made my separate to be 3 different characters [-' ] instead of 1 for a more advanced example. Using PATINDEX as I have done allows me to look for many characters. You could also use CHARINDEX on a single character and this function excepts a third parameter StartFromPosition so I could further simply my 2nd part of the recursion of the pos formula to (assuming a space): pos = CHARINDEX(' ', Name, pos + 1).
The suggested function works fine, however, if you do not want to create any function this is how I do it:
select ID,Name
,string_agg(concat(upper(substring(value,1,1)),lower(substring(value,2,len(value)-1))),' ') as ModifiedName
from Table_Customer
cross apply String_Split(replace(trim(Name),' ',' '),' ')
where Name is not null
group by ID,Name;
The above query split the words by space (' ') and create different rows of each having one substring, then convert the first letter of each substring to upper and keep remaining as lower. The final step is to string aggregate based on the key.
BEGIN
DECLARE #string varchar(100) = 'asdsadsd asdad asd'
DECLARE #ResultString varchar(200) = ''
DECLARE #index int = 1
DECLARE #flag bit = 0
DECLARE #temp varchar(2) = ''
WHILE (#Index <LEN(#string)+1)
BEGIN
SET #temp = SUBSTRING(#string, #Index-1, 1)
--select #temp
IF #temp = ' ' OR #index = 1
BEGIN
SET #ResultString = #ResultString + UPPER(SUBSTRING(#string, #Index, 1))
END
ELSE
BEGIN
SET #ResultString = #ResultString + LOWER(SUBSTRING(#string, #Index, 1))
END
SET #Index = #Index+ 1--increase the index
END
SELECT #ResultString
END
It can be as simple as this:
DECLARE #Name VARCHAR(500) = 'Roger';
SELECT #Name AS Name, UPPER(LEFT(#Name, 1)) + SUBSTRING(#Name, 2, LEN(#Name)) AS CapitalizedName;
fname is column name if fname value is akhil then UPPER(left(fname,1)) provide capital First letter(A) and substring function SUBSTRING(fname,2,LEN(fname)) provide(khil) concate both using + then result is (Akhil)
select UPPER(left(fname,1))+SUBSTRING(fname,2,LEN(fname)) as fname
FROM [dbo].[akhil]
On SQL Server 2016+ using JSON which gives guaranteed order of the words:
CREATE FUNCTION [dbo].[InitCap](#Text NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
RETURN STUFF((
SELECT ' ' + UPPER(LEFT(s.value,1)) + LOWER(SUBSTRING(s.value,2,LEN(s.value)))
FROM OPENJSON('["' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#Text,'\','\\'),'"','\"'),CHAR(9),'\t'),CHAR(10),'\n'),' ','","') + '"]') s
ORDER BY s.[key]
FOR XML PATH(''),TYPE).value('(./text())[1]','NVARCHAR(MAX)'),1,1,'');
END
GO
CREATE FUNCTION [dbo].[Capitalize](#text NVARCHAR(MAX)) RETURNS NVARCHAR(MAX) AS
BEGIN
DECLARE #result NVARCHAR(MAX) = '';
DECLARE #c NVARCHAR(1);
DECLARE #i INT = 1;
DECLARE #isPrevSpace BIT = 1;
WHILE #i <= LEN(#text)
BEGIN
SET #c = SUBSTRING(#text, #i, 1);
SET #result += IIF(#isPrevSpace = 1, UPPER(#c), LOWER(#c));
SET #isPrevSpace = IIF(#c LIKE '[ -]', 1, 0);
SET #i += 1;
END
RETURN #result;
END
GO
DECLARE #sentence NVARCHAR(100) = N'i-thINK-this soLUTION-works-LiKe-a charm';
PRINT dbo.Capitalize(#sentence);
-- I-Think-This Solution-Works-Like-A Charm
Here is the simplest one-liner to do this:
SELECT LEFT(column, 1)+ lower(RIGHT(column, len(column)-1) ) FROM [tablename]
I was looking for the best way to capitalize and i recreate simple sql script
how to use SELECT dbo.Capitalyze('this is a test with multiple spaces')
result "This Is A Test With Multiple Spaces"
CREATE FUNCTION Capitalyze(#input varchar(100) )
returns varchar(100)
as
begin
declare #index int=0
declare #char as varchar(1)=' '
declare #prevCharIsSpace as bit=1
declare #Result as varchar(100)=''
set #input=UPPER(LEFT(#input,1))+LOWER(SUBSTRING(#input, 2, LEN(#input)))
set #index=PATINDEX('% _%',#input)
if #index=0
set #index=len(#input)
set #Result=substring(#input,0,#index+1)
WHILE (#index < len(#input))
BEGIN
SET #index = #index + 1
SET #char=substring(#input,#index,1)
if (#prevCharIsSpace=1)
begin
set #char=UPPER(#char)
if (#char=' ')
set #char=''
end
if (#char=' ')
set #prevCharIsSpace=1
else
set #prevCharIsSpace=0
set #Result=#Result+#char
--print #Result
END
--print #Result
return #Result
end
IF OBJECT_ID ('dbo.fnCapitalizeFirstLetterAndChangeDelimiter') IS NOT NULL
DROP FUNCTION dbo.fnCapitalizeFirstLetterAndChangeDelimiter
GO
CREATE FUNCTION [dbo].[fnCapitalizeFirstLetterAndChangeDelimiter] (#string NVARCHAR(MAX), #delimiter NCHAR(1), #new_delimeter NCHAR(1))
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE #result NVARCHAR(MAX)
SELECT #result = '';
IF (LEN(#string) > 0)
DECLARE #curr INT
DECLARE #next INT
BEGIN
SELECT #curr = 1
SELECT #next = CHARINDEX(#delimiter, #string)
WHILE (LEN(#string) > 0)
BEGIN
SELECT #result =
#result +
CASE WHEN LEN(#result) > 0 THEN #new_delimeter ELSE '' END +
UPPER(SUBSTRING(#string, #curr, 1)) +
CASE
WHEN #next <> 0
THEN LOWER(SUBSTRING(#string, #curr+1, #next-2))
ELSE LOWER(SUBSTRING(#string, #curr+1, LEN(#string)-#curr))
END
IF (#next > 0)
BEGIN
SELECT #string = SUBSTRING(#string, #next+1, LEN(#string)-#next)
SELECT #next = CHARINDEX(#delimiter, #string)
END
ELSE
SELECT #string = ''
END
END
RETURN #result
END
GO

take minus(-) sign number from sting and use in in different procedure

I have variable
DECLARE #Routs NVARCHAR(1024)
#i int
SET #Routs = N'6,4,-5,8'
I need to extract any number from this sting, where it have minus sign before it (-5 in example)
and use it as input parameter with out (-) sing for example #i in different stored procedure.
Pass in you're #Routs parameter to a table valued function that will split the list into a table and then loop through the table and if the value is a negative number execute stored procedure or whatever you want or do nothing if its not negative.
--table function to split parameter by comma
ALTER FUNCTION [dbo].[SplitListOfInts] (#list nvarchar(MAX))
RETURNS #tbl TABLE (number int NOT NULL) AS
BEGIN
DECLARE #pos int,
#nextpos int,
#valuelen int
if len(rtrim(#list)) > 0
begin
SELECT #pos = 0, #nextpos = 1
WHILE #nextpos > 0
BEGIN
SELECT #nextpos = charindex(',', #list, #pos + 1)
SELECT #valuelen = CASE WHEN #nextpos > 0
THEN #nextpos
ELSE len(#list) + 1
END - #pos - 1
INSERT #tbl (number)
VALUES (convert(int, substring(#list, #pos + 1, #valuelen)))
SELECT #pos = #nextpos
END
end
RETURN
END
-- stored procedure that calls that split function and uses #routs parameter
CREATE TABLE #values(nbrValue int)
INSERT INTO #values(nbrValue
EXEC [dbo].[SplitListOfInts] #routs
--if you don't care about non-negatives delete them here
DELETE FROM #values
where nbrValue >= 0
DECLARE #i int
DECLARE #countrows = (SELECT COUNT(nbrValue) FROM #values)
WHILE #countrows >0
SET #i = (SELECT TOP 1 nbrValue FROM #values)
...do what you want
DELETE FROM #values where nbrValue=#i
set #countrows = (SELECT COUNT(nbrValue) FROM #values)
END

Convert textlines in records

I am looking for a way, that I can convert lines of a text in separate records. Perhaps there is someone who has an idea?
I have the following record in a table:
1 blabla Messe\nJahr\nLand
The third field is a textfield. The content is a text with three lines.
now, I should write a select, which gives me as a result three records
1 Memo
2 Jahr
3 Land
i suggest using a cursor and then splitting the string using charpos. as i did not know the name of your table or column, i used table name a, column name a.
declare c cursor for
select a
from a
declare #p varchar(max)
open c
fetch next from c into #p;
while ##FETCH_STATUS = 0
begin
while CHARINDEX('\n',#p,0) > 0
begin
select SUBSTRING(#p,0,charindex('\n',#p,0))
set #p = SUBSTRING(#p,charindex('\n',#p,0)+2, LEN(#p)-charindex('\n',#p,0)-1);
end
select #p;
fetch next from c into #p;
end
DEALLOCATE c
i tested this using
create table a (a varchar(50))
insert into a values ('a\nb\nc')
insert into a values ('d\ne\nf')
use this..
ALTER FUNCTION [dbo].[GetWordsFromString]
(
#string nvarchar(max)
)
RETURNS
#out TABLE
(
Name nvarchar(200)
)
AS
BEGIN
DECLARE #pos int,
#nextpos int,
#valuelen int
SELECT #pos = 0, #nextpos = 1
WHILE #nextpos > 0
BEGIN
SELECT #nextpos = charindex('\', #string, #pos + 1)
SELECT #valuelen = CASE WHEN #nextpos > 0
THEN #nextpos
ELSE len(#string) + 1
END - #pos - 1
INSERT #out
VALUES (convert(nvarchar, substring(#string, #pos + 1, #valuelen)))
SELECT #pos = #nextpos
END
RETURN
END

Delete records from table which ids is NOT based on a list of ids (which is nvarchar) separated by comma

I need your help regarding the following situation in SQL Server 2008R2.
In SQL, I have a list of ids saved as NVARCHAR(MAX) like N('1,2,3,4,5')
I read this How to convert comma separated NVARCHAR to table records in SQL Server 2005?
In this scope, I wrote a function for this:
ALTER FUNCTION [dbo].[func$intlist_to_tbl] (#list nvarchar(MAX))
RETURNS #tbl TABLE (number int NOT NULL) AS
BEGIN
DECLARE #pos int,
#nextpos int,
#valuelen int
SELECT #pos = 0, #nextpos = 1
WHILE #nextpos > 0
BEGIN
SELECT #nextpos = charindex(',', #list, #pos + 1)
SELECT #valuelen = CASE WHEN #nextpos > 0
THEN #nextpos
ELSE len(#list) + 1
END - #pos - 1
INSERT #tbl (number)
VALUES (convert(int, substring(#list, #pos + 1, #valuelen)))
SELECT #pos = #nextpos
END
RETURN
END
Ok, I want to delete some records which id IS NOT found in above list.
How to do that ?
I tried something like:
DELETE a_ FROM TableA a_
LEFT JOIN func$intlist_to_tbl(#idList) _tmp
ON _tmp.number = a_.ID_
WHERE a_.ID IS NULL
But is not correct.
Maybe something similar?
DELETE FROM
TableA a_
where
a_.id not in (select number from func$intlist_to_tbl(#idList))

How to capitalize the first letter of each word in a string in SQL Server

What’s the best way to capitalize the first letter of each word in a string in SQL Server.
From http://www.sql-server-helper.com/functions/initcap.aspx
CREATE FUNCTION [dbo].[InitCap] ( #InputString varchar(4000) )
RETURNS VARCHAR(4000)
AS
BEGIN
DECLARE #Index INT
DECLARE #Char CHAR(1)
DECLARE #PrevChar CHAR(1)
DECLARE #OutputString VARCHAR(255)
SET #OutputString = LOWER(#InputString)
SET #Index = 1
WHILE #Index <= LEN(#InputString)
BEGIN
SET #Char = SUBSTRING(#InputString, #Index, 1)
SET #PrevChar = CASE WHEN #Index = 1 THEN ' '
ELSE SUBSTRING(#InputString, #Index - 1, 1)
END
IF #PrevChar IN (' ', ';', ':', '!', '?', ',', '.', '_', '-', '/', '&', '''', '(')
BEGIN
IF #PrevChar != '''' OR UPPER(#Char) != 'S'
SET #OutputString = STUFF(#OutputString, #Index, 1, UPPER(#Char))
END
SET #Index = #Index + 1
END
RETURN #OutputString
END
GO
There is a simpler/smaller one here (but doesn't work if any row doesn't have spaces, "Invalid length parameter passed to the RIGHT function."):
http://www.devx.com/tips/Tip/17608
As a table-valued function:
CREATE FUNCTION dbo.InitCap(#v AS VARCHAR(MAX))
RETURNS TABLE
AS
RETURN
WITH a AS (
SELECT (
SELECT UPPER(LEFT(value, 1)) + LOWER(SUBSTRING(value, 2, LEN(value))) AS 'data()'
FROM string_split(#v, ' ')
ORDER BY CHARINDEX(value,#v)
FOR XML PATH (''), TYPE) ret)
SELECT CAST(a.ret AS varchar(MAX)) ret from a
GO
Note that string_split requires COMPATIBILITY_LEVEL 130.
A variation of the one I've been using for quite some time is:
CREATE FUNCTION [widget].[properCase](#string varchar(8000)) RETURNS varchar(8000) AS
BEGIN
SET #string = LOWER(#string)
DECLARE #i INT
SET #i = ASCII('a')
WHILE #i <= ASCII('z')
BEGIN
SET #string = REPLACE( #string, ' ' + CHAR(#i), ' ' + CHAR(#i-32))
SET #i = #i + 1
END
SET #string = CHAR(ASCII(LEFT(#string, 1))-32) + RIGHT(#string, LEN(#string)-1)
RETURN #string
END
You can easily modify to handle characters after items other than spaces if you wanted to.
Another solution without using the loop - pure set-based approach with recursive CTE
create function [dbo].InitCap (#value varchar(max))
returns varchar(max) as
begin
declare
#separator char(1) = ' ',
#result varchar(max) = '';
with r as (
select value, cast(null as varchar(max)) [x], cast('' as varchar(max)) [char], 0 [no] from (select rtrim(cast(#value as varchar(max))) [value]) as j
union all
select right(value, len(value)-case charindex(#separator, value) when 0 then len(value) else charindex(#separator, value) end) [value]
, left(r.[value], case charindex(#separator, r.value) when 0 then len(r.value) else abs(charindex(#separator, r.[value])-1) end ) [x]
, left(r.[value], 1)
, [no] + 1 [no]
from r where value > '')
select #result = #result +
case
when ascii([char]) between 97 and 122
then stuff(x, 1, 1, char(ascii([char])-32))
else x
end + #separator
from r where x is not null;
set #result = rtrim(#result);
return #result;
end
If you are looking for the answer to the same question in Oracle/PLSQL then you may use the function INITCAP. Below is an example for the attribute dname from a table department which has the values ('sales', 'management', 'production', 'development').
SQL> select INITCAP(dname) from department;
INITCAP(DNAME)
--------------------------------------------------
Sales
Management
Production
Development
;WITH StudentList(Name) AS (
SELECT CONVERT(varchar(50), 'Carl-VAN')
UNION SELECT 'Dean o''brian'
UNION SELECT 'Andrew-le-Smith'
UNION SELECT 'Eddy thompson'
UNION SELECT 'BOBs-your-Uncle'
), Student AS (
SELECT CONVERT(varchar(50), UPPER(LEFT(Name, 1)) + LOWER(SUBSTRING(Name, 2, LEN(Name)))) Name,
pos = PATINDEX('%[-'' ]%', Name)
FROM StudentList
UNION ALL
SELECT CONVERT(varchar(50), LEFT(Name, pos) + UPPER(SUBSTRING(Name, pos + 1, 1)) + SUBSTRING(Name, pos + 2, LEN(Name))) Name,
pos = CASE WHEN PATINDEX('%[-'' ]%', RIGHT(Name, LEN(Name) - pos)) = 0 THEN 0 ELSE pos + PATINDEX('%[-'' ]%', RIGHT(Name, LEN(Name) - pos)) END
FROM Student
WHERE pos > 0
)
SELECT Name
FROM Student
WHERE pos = 0
ORDER BY Name
This will result in:
Andrew-Le-Smith
Bobs-Your-Uncle
Carl-Van
Dean O'Brian
Eddy Thompson
Using a recursive CTE set based query should out perform a procedural while loop query.
Here I also have made my separate to be 3 different characters [-' ] instead of 1 for a more advanced example. Using PATINDEX as I have done allows me to look for many characters. You could also use CHARINDEX on a single character and this function excepts a third parameter StartFromPosition so I could further simply my 2nd part of the recursion of the pos formula to (assuming a space): pos = CHARINDEX(' ', Name, pos + 1).
The suggested function works fine, however, if you do not want to create any function this is how I do it:
select ID,Name
,string_agg(concat(upper(substring(value,1,1)),lower(substring(value,2,len(value)-1))),' ') as ModifiedName
from Table_Customer
cross apply String_Split(replace(trim(Name),' ',' '),' ')
where Name is not null
group by ID,Name;
The above query split the words by space (' ') and create different rows of each having one substring, then convert the first letter of each substring to upper and keep remaining as lower. The final step is to string aggregate based on the key.
BEGIN
DECLARE #string varchar(100) = 'asdsadsd asdad asd'
DECLARE #ResultString varchar(200) = ''
DECLARE #index int = 1
DECLARE #flag bit = 0
DECLARE #temp varchar(2) = ''
WHILE (#Index <LEN(#string)+1)
BEGIN
SET #temp = SUBSTRING(#string, #Index-1, 1)
--select #temp
IF #temp = ' ' OR #index = 1
BEGIN
SET #ResultString = #ResultString + UPPER(SUBSTRING(#string, #Index, 1))
END
ELSE
BEGIN
SET #ResultString = #ResultString + LOWER(SUBSTRING(#string, #Index, 1))
END
SET #Index = #Index+ 1--increase the index
END
SELECT #ResultString
END
It can be as simple as this:
DECLARE #Name VARCHAR(500) = 'Roger';
SELECT #Name AS Name, UPPER(LEFT(#Name, 1)) + SUBSTRING(#Name, 2, LEN(#Name)) AS CapitalizedName;
fname is column name if fname value is akhil then UPPER(left(fname,1)) provide capital First letter(A) and substring function SUBSTRING(fname,2,LEN(fname)) provide(khil) concate both using + then result is (Akhil)
select UPPER(left(fname,1))+SUBSTRING(fname,2,LEN(fname)) as fname
FROM [dbo].[akhil]
On SQL Server 2016+ using JSON which gives guaranteed order of the words:
CREATE FUNCTION [dbo].[InitCap](#Text NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
RETURN STUFF((
SELECT ' ' + UPPER(LEFT(s.value,1)) + LOWER(SUBSTRING(s.value,2,LEN(s.value)))
FROM OPENJSON('["' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#Text,'\','\\'),'"','\"'),CHAR(9),'\t'),CHAR(10),'\n'),' ','","') + '"]') s
ORDER BY s.[key]
FOR XML PATH(''),TYPE).value('(./text())[1]','NVARCHAR(MAX)'),1,1,'');
END
GO
CREATE FUNCTION [dbo].[Capitalize](#text NVARCHAR(MAX)) RETURNS NVARCHAR(MAX) AS
BEGIN
DECLARE #result NVARCHAR(MAX) = '';
DECLARE #c NVARCHAR(1);
DECLARE #i INT = 1;
DECLARE #isPrevSpace BIT = 1;
WHILE #i <= LEN(#text)
BEGIN
SET #c = SUBSTRING(#text, #i, 1);
SET #result += IIF(#isPrevSpace = 1, UPPER(#c), LOWER(#c));
SET #isPrevSpace = IIF(#c LIKE '[ -]', 1, 0);
SET #i += 1;
END
RETURN #result;
END
GO
DECLARE #sentence NVARCHAR(100) = N'i-thINK-this soLUTION-works-LiKe-a charm';
PRINT dbo.Capitalize(#sentence);
-- I-Think-This Solution-Works-Like-A Charm
Here is the simplest one-liner to do this:
SELECT LEFT(column, 1)+ lower(RIGHT(column, len(column)-1) ) FROM [tablename]
I was looking for the best way to capitalize and i recreate simple sql script
how to use SELECT dbo.Capitalyze('this is a test with multiple spaces')
result "This Is A Test With Multiple Spaces"
CREATE FUNCTION Capitalyze(#input varchar(100) )
returns varchar(100)
as
begin
declare #index int=0
declare #char as varchar(1)=' '
declare #prevCharIsSpace as bit=1
declare #Result as varchar(100)=''
set #input=UPPER(LEFT(#input,1))+LOWER(SUBSTRING(#input, 2, LEN(#input)))
set #index=PATINDEX('% _%',#input)
if #index=0
set #index=len(#input)
set #Result=substring(#input,0,#index+1)
WHILE (#index < len(#input))
BEGIN
SET #index = #index + 1
SET #char=substring(#input,#index,1)
if (#prevCharIsSpace=1)
begin
set #char=UPPER(#char)
if (#char=' ')
set #char=''
end
if (#char=' ')
set #prevCharIsSpace=1
else
set #prevCharIsSpace=0
set #Result=#Result+#char
--print #Result
END
--print #Result
return #Result
end
IF OBJECT_ID ('dbo.fnCapitalizeFirstLetterAndChangeDelimiter') IS NOT NULL
DROP FUNCTION dbo.fnCapitalizeFirstLetterAndChangeDelimiter
GO
CREATE FUNCTION [dbo].[fnCapitalizeFirstLetterAndChangeDelimiter] (#string NVARCHAR(MAX), #delimiter NCHAR(1), #new_delimeter NCHAR(1))
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE #result NVARCHAR(MAX)
SELECT #result = '';
IF (LEN(#string) > 0)
DECLARE #curr INT
DECLARE #next INT
BEGIN
SELECT #curr = 1
SELECT #next = CHARINDEX(#delimiter, #string)
WHILE (LEN(#string) > 0)
BEGIN
SELECT #result =
#result +
CASE WHEN LEN(#result) > 0 THEN #new_delimeter ELSE '' END +
UPPER(SUBSTRING(#string, #curr, 1)) +
CASE
WHEN #next <> 0
THEN LOWER(SUBSTRING(#string, #curr+1, #next-2))
ELSE LOWER(SUBSTRING(#string, #curr+1, LEN(#string)-#curr))
END
IF (#next > 0)
BEGIN
SELECT #string = SUBSTRING(#string, #next+1, LEN(#string)-#next)
SELECT #next = CHARINDEX(#delimiter, #string)
END
ELSE
SELECT #string = ''
END
END
RETURN #result
END
GO