I don't want to create a custom function for that if such function already exists in SQL Server.
Input string: This is my string to convert
Expected output: This Is My String To Convert
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
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(4000)
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 (' ', ';', ':', '!', '?', ',', '.', '_', '-', '/', '&', '''', '(')
SET #OutputString = STUFF(#OutputString, #Index, 1, UPPER(#Char))
SET #Index = #Index + 1
END
RETURN #OutputString
END
Declare #str nvarchar(100)
SET #str = 'my string to convert'
SELECT #str = [dbo].[InitCap](#str)
SELECT #str
AFAIK, SQL Server has no built-in function for this.
You have to write custom function for it.
Try this.
CREATE FUNCTION [dbo].[CamelCase]
(#Str varchar(8000))
RETURNS varchar(8000) AS
BEGIN
DECLARE #Result varchar(2000)
SET #Str = LOWER(#Str) + ' '
SET #Result = ''
WHILE 1=1
BEGIN
IF PATINDEX('% %',#Str) = 0 BREAK
SET #Result = #Result + UPPER(Left(#Str,1))+
SubString (#Str,2,CharIndex(' ',#Str)-1)
SET #Str = SubString(#Str,
CharIndex(' ',#Str)+1,Len(#Str))
END
SET #Result = Left(#Result,Len(#Result))
RETURN #Result
END
Output :
Input String : 'microSoft sql server'
Output String : 'Microsoft Sql Server'
I'd have to go with "No, that does not exist". This based on several years of perusing the available string-functions in T-SQL and some pretty recent 5-day courses in SQL Server 2008 R2.
Of course, I still could be wrong :).
If the goal of your operation is to prettify strings of Names then proper capitalization could be defined as the first letter of each word separated by non-alphabet characters.
Other solutions do not take into account:
Preserving spacing (especially trailing spaces).
Preserving NULL, empty-string, or a string of just spaces.
Handling more than just spaces (e.g. dashes, commas, underscores, etc...)
Handling more than one non-alpha character between words/tokens.
Handling exceptions (e.g. McDonald or III like in "James William
Bottomtooth the III").
Note: My solution does not handle exceptions.
If you are very concerned about those, then I suggest writing a CLR C# assembly for those as it will be tricky, and strings are an area where C# excels.
Another solution on here tries to account for this, but it would still take "ivan terrible the iv" and output "**IV***an Terrible The IV*".
This is the function I came up with:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fs_PascalCase]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[fs_PascalCase]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fs_PascalCase]
(
#Text nVarChar(MAX)
)
RETURNS nVarChar(MAX)
AS
BEGIN
SET #Text = LOWER(#Text)--This step is optional. Keep if you want the code below to control all casing. - 11/26/2013 - MCR.
DECLARE #New nVarChar(MAX) = (CASE WHEN #Text IS NULL THEN NULL ELSE '' END)--Still return null when source is null. - 11/26/2013 - MCR.
DECLARE #Len Int = LEN(REPLACE(#Text, ' ', '_'))--If you want to count/keep trailing-spaces, you MUST use this!!! - 11/26/2013 - MCR.
DECLARE #Index Int = 1--Sql-Server is 1-based, not 0-based.
WHILE (#Index <= #Len)
IF (SUBSTRING(#Text, #Index, 1) LIKE '[^a-z]' AND #Index + 1 <= #Len)--If not alpha and there are more character(s).
SELECT #New = #New + UPPER(SUBSTRING(#Text, #Index, 2)), #Index = #Index + 2
ELSE
SELECT #New = #New + SUBSTRING(#Text, #Index, 1) , #Index = #Index + 1
--If #Text is null, then #Len will be Null, and everything will be null.
--If #Text is '', then (#Len - 1) will be -1, so ABS() it to use 1 instead, which will still return ''.
RETURN ( UPPER(LEFT(#New, 1)) + RIGHT(#New, ABS(#Len - 1)) )
END
GO
You would call it like so:
SELECT dbo.fs_PascalCase(NULL)[Null],
dbo.fs_PascalCase('')[EmptyString],
dbo.fs_PascalCase('hello how are-you TODAY ')[LongString]
The output will look like this:
My Strategy
If the name is already in mixed case, trust that it’s right.
If the name is not in mixed case, then do the following:
Trim up the name to eliminate white space
Account for the names that start with “Mc” like “McDavid”
Account for names with apostrophes like O’Reilly
Account for hyphenated names (married names) “Anderson-Johnson”
Account for multiple word names like “La Russa”
Make sure suffixes included in the names field are capitalized appropriately
The Code
Here's my original post on this: Converting String to Camel Case in SQL Server
CREATE FUNCTION [dbo].[GetCamelCaseName]
(
#Name varchar(50)
)
RETURNS VARCHAR(50) WITH SCHEMABINDING
AS
BEGIN
-- Declare the return variable here
DECLARE #NameCamelCase VARCHAR(50)
-- This is determining whether or not the name is in camel case already (if the 1st character is uppercase
-- and the third is lower (because the 2nd could be an apostrophe). To do this, you have to cast the
-- character as varbinary and compare it with the upper case of the character cast as varbinary.
IF (CAST(SUBSTRING(#Name, 1,1) as varbinary) = CAST(SUBSTRING(UPPER(#Name), 1, 1) as varbinary)
AND ((CAST(SUBSTRING(#Name, 2,1) as varbinary) = CAST(SUBSTRING(LOWER(#Name), 2, 1) as varbinary)
AND SUBSTRING(#Name, 2,1) != '''')
or
(CAST(SUBSTRING(#Name, 4,1) as varbinary) = CAST(SUBSTRING(LOWER(#Name), 4, 1) as varbinary)
AND SUBSTRING(#Name, 2,1) = '''')))
BEGIN
SELECT #NameCamelCase = RTRIM(LTRIM(#Name))
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' sr', ' Sr')
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' jr', ' Jr')
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' ii', ' II')
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' iii', ' III')
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' DE ', ' de ')
SELECT #NameCamelCase = REPLACE(#NameCamelCase, 'macdonald', 'MacDonald')
if (#NameCamelCase LIKE '% iv') -- avoid changing "Ivan" to "IVan"
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' iv', ' IV')
if ((#NameCamelCase = 'i') or (#NameCamelCase = 'ii') or (#NameCamelCase = 'iii') or (#NameCamelCase = 'iv'))
SELECT #NameCamelCase = UPPER(#NameCamelCase)
RETURN #NameCamelCase
END
ELSE
BEGIN
SELECT #NameCamelCase = RTRIM(LTRIM(#Name))
-- "Mc-"
SELECT #NameCamelCase =
CASE
WHEN #Name LIKE 'mc%'
THEN UPPER(SUBSTRING(#Name, 1, 1)) + LOWER(SUBSTRING(#Name, 2, 1)) + UPPER(SUBSTRING(#Name, 3, 1)) + LOWER(SUBSTRING(#Name, 4, 47))
ELSE
UPPER(SUBSTRING(#Name, 1, 1)) + LOWER(SUBSTRING(#Name, 2, 49))
END
-- Apostrophes
SELECT #NameCamelCase =
CASE
WHEN #NameCamelCase LIKE '%''%'
THEN SUBSTRING(#NameCamelCase, 1, CHARINDEX('''', #NameCamelCase) - 1) + '''' + UPPER(SUBSTRING(#NameCamelCase, CHARINDEX('''', #NameCamelCase) + 1, 1)) + SUBSTRING(#NameCamelCase, CHARINDEX('''', #NameCamelCase) + 2, 50)
ELSE
#NameCamelCase
END
-- Hyphenated names (do it twice to account for double hyphens)
SELECT #NameCamelCase =
CASE
WHEN #NameCamelCase LIKE '%-%'
THEN SUBSTRING(#NameCamelCase, 1, CHARINDEX('-', #NameCamelCase) - 1) + '^' + UPPER(SUBSTRING(#NameCamelCase, CHARINDEX('-', #NameCamelCase) + 1, 1)) + SUBSTRING(#NameCamelCase, CHARINDEX('-', #NameCamelCase) + 2, 50)
ELSE
#NameCamelCase
END
SELECT #NameCamelCase =
CASE
WHEN #NameCamelCase LIKE '%-%'
THEN SUBSTRING(#NameCamelCase, 1, CHARINDEX('-', #NameCamelCase) - 1) + '^' + UPPER(SUBSTRING(#NameCamelCase, CHARINDEX('-', #NameCamelCase) + 1, 1)) + SUBSTRING(#NameCamelCase, CHARINDEX('-', #NameCamelCase) + 2, 50)
ELSE
#NameCamelCase
END
SELECT #NameCamelCase = REPLACE(#NameCamelCase, '^', '-')
-- Multiple word names (do it twice to account for three word names)
SELECT #NameCamelCase =
CASE
WHEN #NameCamelCase LIKE '% %'
THEN SUBSTRING(#NameCamelCase, 1, CHARINDEX(' ', #NameCamelCase) - 1) + '?' + UPPER(SUBSTRING(#NameCamelCase, CHARINDEX(' ', #NameCamelCase) + 1, 1)) + SUBSTRING(#NameCamelCase, CHARINDEX(' ', #NameCamelCase) + 2, 50)
ELSE
#NameCamelCase
END
SELECT #NameCamelCase =
CASE
WHEN #NameCamelCase LIKE '% %'
THEN SUBSTRING(#NameCamelCase, 1, CHARINDEX(' ', #NameCamelCase) - 1) + '?' + UPPER(SUBSTRING(#NameCamelCase, CHARINDEX(' ', #NameCamelCase) + 1, 1)) + SUBSTRING(#NameCamelCase, CHARINDEX(' ', #NameCamelCase) + 2, 50)
ELSE
#NameCamelCase
END
SELECT #NameCamelCase = REPLACE(#NameCamelCase, '?', ' ')
-- Names in Parentheses
SELECT #NameCamelCase =
CASE
WHEN #NameCamelCase LIKE '%(%'
THEN SUBSTRING(#NameCamelCase, 1, CHARINDEX('(', #NameCamelCase) - 1) + '(' + UPPER(SUBSTRING(#NameCamelCase, CHARINDEX('(', #NameCamelCase) + 1, 1)) + SUBSTRING(#NameCamelCase, CHARINDEX('(', #NameCamelCase) + 2, 50)
ELSE
#NameCamelCase
END
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' sr', ' Sr')
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' jr', ' Jr')
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' ii', ' II')
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' iii', ' III')
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' DE ', ' de ')
SELECT #NameCamelCase = REPLACE(#NameCamelCase, 'macdonald', 'MacDonald')
if (#NameCamelCase LIKE '% iv')
SELECT #NameCamelCase = REPLACE(#NameCamelCase, ' iv', ' IV')
if ((#NameCamelCase = 'i') or (#NameCamelCase = 'ii') or (#NameCamelCase = 'iii') or (#NameCamelCase = 'iv'))
SELECT #NameCamelCase = UPPER(#NameCamelCase)
-- Return the result of the function
RETURN ISNULL(#NameCamelCase, '')
END
RETURN ISNULL(#NameCamelCase, '')
END
With SQL 2017 the function could look like this:
create function dbo.cap_words (#str varchar(max))
returns varchar(max)
as
begin
declare #result varchar(max);
select #result = string_agg( upper(left(value,1)) + substring(value,2,999),' ') from string_split(lower(#str),' ')
return #result;
end
Like me, many people may be looking for an in-query solution, query creating function, well I figured out a different approach:
SELECT REPLACE(
STUFF(
(SELECT' '+ LTRIM(RTRIM(UPPER(SUBSTRING(value, 1,1))+LOWER(SUBSTRING(value, 2, LEN(value)))))
FROM STRING_SPLIT([Message], ' ')
FOR XML PATH('')
), 1, 1, ''
), ''/*Control delimiters here*/, '') FROM [dbo].[MessageQueue]
Change [MessageQueue] table for your own table, and [Message] for your field.
The function STRING_SPLIT may require to increase your SQL compatibility level to 130.
Use the outer REPLACE function to set any delimiter you want.
Here is simple thing, don't make it complicated.
Oracle:
SELECT initcap(lower('This is MY striNg to conVerT')) FROM dual;
Related
I have a sql table that contains an employee's full name in all caps (i.e. SMITH-EASTMAN,JIM M).
I need to be able to separate the full name into two separate columns (Last Name and First Name). This part is going well. Now I could use some assistance with removing the capital letters and putting it in normal case.
How can I take the results of my common table expression and pass them into a function?
WITH CTE AS
(
SELECT FullName = [Employee Name],
LastName = SUBSTRING([Employee Name], 1, CHARINDEX(',',[Employee Name])-1),
FirstNameStartPos = CHARINDEX(',',[Employee Name]) + 1,
MidlleInitialOrFirstNameStartPos = CHARINDEX(' ',[Employee Name]),
MiddleInitialOrSecondFirstName = SUBSTRING([Employee Name], CHARINDEX(' ',[Employee Name]),LEN([Employee Name])),
MiddleInitialOrSecondFirstNameLen = LEN(SUBSTRING([Employee Name], CHARINDEX(' ',[Employee Name]),LEN([Employee Name]))) - 1
FROM ['Med-PS PCN Mapping$']
WHERE [PS Employee ID] IS NOT NULL
),
CTE2 AS
(
SELECT FullName = CTE.FullName,
DerivedFirstName = CASE
WHEN CTE.MiddleInitialOrSecondFirstNameLen = 1
THEN SUBSTRING(CTE.FullName, CTE.FirstNameStartPos, CTE.MidlleInitialOrFirstNameStartPos - CTE.FirstNameStartPos)
ELSE SUBSTRING(CTE.FullName, CTE.FirstNameStartPos, CTE.FirstNameStartPos + CTE.MiddleInitialOrSecondFirstNameLen)
END,
DerivedLastName = CTE.LastName
FROM CTE
)
SELECT *
FROM CTE2
RESULTS
FullName DerivedFirstName DerivedLastName
SMITH-EASTMAN,JIM M JIM SMITH-EASTMAN
O'DAY,MARTIN C MARTIN O'DAY
TROUT,MADISON MARIE MADISON MARI TROUT
CREATE FUNCTION [dbo].[FixCap] ( #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
select [dbo].[FixCap] (pass in DerivedFirstName from CTE2);
select [dbo].[FixCap] (pass in DerivedLastName from CTE2);
Do you want something like INITCAP ?
CREATE FUNCTION dbo.F_INITCAP (#PHRASE NVARCHAR(max))
RETURNS NVARCHAR(max)
WITH RETURNS NULL ON NULL INPUT
AS
BEGIN
IF LEN(#PHRASE) < 1 RETURN #PHRASE;
DECLARE #I INT = 1, #C CHAR(1), #P BIT = 0, #OUT VARCHAR(max) = '';
WHILE #I <= LEN(#PHRASE)
BEGIN
SET #C = SUBSTRING(#PHRASE, #I, 1);
IF #C BETWEEN 'A' AND 'Z' COLLATE Latin1_General_CI_AI
BEGIN
IF #P = 0
SET #OUT = #OUT + UPPER(#C);
ELSE
SET #OUT = #OUT + LOWER(#C);
SET #P = 1
END
ELSE
BEGIN
SET #P = 0;
SET #OUT = #OUT + LOWER(#C);
END
SET #I = #I + 1;
END
RETURN #OUT;
END
GO
I detect and process the first and second words of the written sentence. What I want to do is detect and process the third and fourth words. There are examples and explanations in the picture. Thanks for your answers.
Declare
#FirstWord varchar(16),
#SecondWord varchar(16),
#ThirdWord varchar(16),
#FourthWord varchar(16)
SET #FirstWord = LEFT(#Message,LEN(#Message)-CHARINDEX(' ',REVERSE(#Message),1))
SET #SecondWord = CAST(RIGHT(#Message,LEN(#Message)-CHARINDEX(' ',#Message,1)) as int)
/* how do i catch the third and fourth word
SET #ThirdWord = ???????????????????
SET #FourthWord = ???????????????????
*/
IF #FirstWord = 'hello' and #SecondWord = 1
begin
INSERT INTO [dbo].[_Message] (Message) Values ('The first word you wrote = '+Convert (varchar(16), #FirstWord)+' The second word you type = '+Convert (varchar(16), #SecondWord)+' ')
end
What needs to be done is to learn the third and fourth word in the same way.
I'm not sure why you are using reverse() if you want the first words in the message. In any case, you can just pop off the first word and repeat this process for each word:
declare #rest varchar(max);
set #rest = #message;
select #firstword = left(#rest, charindex(' ', #rest + ' ') - 1);
set #rest = stuff(#rest, 1, charindex(' ', #rest), '');
select #secondword = left(#rest, charindex(' ', #rest + ' ') - 1);
set #rest = stuff(#rest, 1, charindex(' ', #rest), '');
select #thirdword = left(#rest, charindex(' ', #rest + ' ') - 1);
set #rest = stuff(#rest, 1, charindex(' ', #rest), '');
select #fourthword = left(#rest, charindex(' ', #rest + ' ') - 1);
set #rest = stuff(#rest, 1, charindex(' ', #rest), '');
select #firstword, #secondword, #thirdword, #fourthword;
Here is a db<>fiddle.
Note that this type of operation is suspicious. First, SQL Server is not the best tool for parsing strings. And if you are going to split a #message, you should probably split all the words and store the results in a temporary table of some sort. Then you can process the table.
I've a Dynamic SQL that is required to be optimized. I need to make CASE Expression Dynamic. I've a list of ATTRIBUTE_LIST & SCENARIO_LIST, that are provided below. I wrote a Function to get them Dynamically. How can I replace Three CASE Expression and make it Dynamic? I'm trying to avoid hard coding.
SET #ATTRIBUTE_LIST = 'symbol_type, currency, performing_status' -- INPUTS
SET #SCENARIO_LIST = 'historicalsimulation_1day_end_10dec2013, historicalsimulation_1day_end_11dec2013'
SELECT CASE
WHEN (GROUPING(Scenario_Name) = 1) THEN ''ALL''
WHEN (Scenario_Name = ''[BaseCase]'') THEN ''BaseCase''
ELSE ISNULL(Scenario_Name, '''')
END AS Scenario_Name,
CASE
WHEN (GROUPING(Symbol_Type) = 1) THEN ''ALL''
ELSE ISNULL(Symbol_Type, '''')
END AS Symbol_Type,
CASE
WHEN (GROUPING(Currency) = 1) THEN ''ALL''
ELSE ISNULL(Currency, '''')
END AS Currency,
CASE
WHEN (GROUPING(Performing_Status) = 1) THEN ''ALL''
ELSE ISNULL(Performing_Status, '''') \
END AS Performing_Status,
SUM(Value) AS ScenarioValue
FROM [20151005_171003_UserName_NT-22_Analysis_Tue] o
LEFT JOIN [20151005_171003_UserName_NT-22_Analysis_Tue_Position_Data] pld
ON o.Position_Unique_Identifier=pld.Position_Unique_Identifier
GROUP BY ' + #ATTRIBUTE_LIST + ' WITH CUBE) AS DATA
PIVOT ( Sum(scenariovalue)
FOR scenario_name IN (' + #SCENARIO_LIST + ')'
It appears you are using SQL Server. Here's a brute-force way of looping over your attributes and building a series of case expressions:
declare #cases nvarchar(max) = '';
declare #l varchar(max) = #ATTRIBUTE_LIST + ',';
declare #ofs int = 0;
declare #pos int = charindex(',', #l, #ofs + 1);
while #pos > 0
begin
if #cases <> '' set #cases = #cases + ',';
set #cases = #cases +
replace('
CASE WHEN (GROUPING(<COL>) = 1) THEN ''ALL''
ELSE ISNULL(<COL>, '''')
END AS <COL>',
'<COL>', substring(#l, #ofs + 1, #pos - #ofs - 1)
);
set #ofs = #pos;
set #pos = charindex(',', #l, #ofs + 1);
end
select #cases;
I'm trying to extract a number that follows an cardinal "#" from a String in sql server. Also I want to ignore all numbers that aren't attached to the "#" simbol. For that purpose I created something like this:
DECLARE #val nvarchar(50)
SET #val = '#5777 some text'
PRINT SUBSTRING(#val, PATINDEX('%#[0-9]%', #val) + 1,
PATINDEX('%[^0-9]%', SUBSTRING(#val,
PATINDEX('%#[0-9]%', #val) + 1, LEN(#val))) - 1)
----------
#val = '#5777 some text':
result = 5777
#val = '#5777'
result = error
It works fine if the number the number as some text after it but if the number is the last character I obvisualy get an error stating:
"
Invalid length parameter passed to the LEFT or SUBSTRING function
"
Of course I could do something like:
DECLARE #val nvarchar(50)
SET #val = '#5777'
PRINT SUBSTRING(#val, PATINDEX('%#[0-9]%', #val) + 1,
CASE WHEN PATINDEX('%[^0-9]%', SUBSTRING(#val,
PATINDEX('%#[0-9]%', #val) + 1, LEN(#val))) = 0 THEN
LEN(#val) ELSE
PATINDEX('%[^0-9]%', SUBSTRING(#val,
PATINDEX('%#[0-9]%', #val) + 1, LEN(#val))) - 1
END)
----------
result = 5777
So my question is: Is there any way to achieve this purpose in a simpler and more efficient way?
Thank you
A bit hacky, but it works for both of your scenarios (following text, no following text):
DECLARE #val nvarchar(50)
SET #val = '#5777 some text'
PRINT SUBSTRING(#val, PATINDEX('%#[0-9]%', #val) + 1,
ISNULL(NULLIF((PATINDEX('%[^0-9]%', SUBSTRING(#val, PATINDEX('%#[0-9]%', #val) + 1, LEN(#val))) - 1),-1),100))
SET #val = '#5777'
PRINT SUBSTRING(#val, PATINDEX('%#[0-9]%', #val) + 1,
ISNULL(NULLIF((PATINDEX('%[^0-9]%', SUBSTRING(#val, PATINDEX('%#[0-9]%', #val) + 1, LEN(#val))) - 1),-1),100))
DECLARE #val nvarchar(50)
SET #val = '#5777 some text'
PRINT REPLACE(#val, SUBSTRING(#val, PATINDEX('%[^a-zA-Z0-9 ]%', #val), 1), '')
If you'll be parsing strings on a regular basis, add a string-splitting function to your toolbox.
SELECT string
FROM dbo.SplitString(#value,' ')
WHERE
string LIKE '#'+REPLICATE('[0-9]',LEN(string)-1)
I'm looking for a way to do this ...
SELECT FirstName, LastName, Split(AddressBlock, ' ', 1), Split(AddressBlock, ' ', 2), PostCode
FROM Contacts
The arguments I want to pass are ...
The address
The separator (current situation requires 2 spaces but this might be a comma or a space followed by a comma) or something else (it varies).
The address part I want to return (i don't always need all parts of the split result).
I seem to be able to find a few examples of splitting functions about the internet but they return a table containing the entire set of split parts.
My SQL skills aren't that great so I need the answer to be ultra simple.
I'm always working with nvarchar data and the function needs to be reusable.
If you want a user-defined function to do this, this should work. Not that pretty, but...
CREATE FUNCTION dbo.SplitStringPart (
#input nvarchar(MAX),
#separator nvarchar(10),
#index int
) RETURNS nvarchar(MAX)
BEGIN
DECLARE #counter int,
#position int,
#oldposition int,
#separatorlength int,
#result nvarchar(MAX)
SET #separatorlength = DATALENGTH(#separator) / 2
IF #separatorlength = 0 RETURN NULL
SET #result = NULL
SET #counter = 1
SET #position = -2
WHILE (#counter <= #index)
BEGIN
SET #oldposition = #position
SET #position = CHARINDEX(#separator, #input, #position + 1)
IF #position = 0 AND #counter < #index
BEGIN
SET #oldposition = 0
BREAK
END
SET #counter = #counter + 1
END
IF #oldposition = 0 AND #position = 0
RETURN NULL
ELSE IF #oldposition < 0
BEGIN
IF #position = 0 AND #index = 1
SET #result = #input
ELSE
SET #result = SUBSTRING(#input, 0, #position)
END
ELSE IF #position <= 0
SET #result = SUBSTRING(#input, #oldposition + #separatorlength, LEN(#input) - #oldposition - #separatorlength)
ELSE
SET #result = SUBSTRING(#input, #oldposition + #separatorlength, #position - #oldposition - #separatorlength)
RETURN #result
END
GO
It's not pretty, but add this to you SQL statement and it should work:
CASE
WHEN charindex(' ', substring(AddressBlock, (charindex(' ', AddressBlock) + 1), len(AddressBlock))) > 0 THEN substring(AddressBlock, (charindex(' ', AddressBlock) + 1), charindex(' ', substring(AddressBlock, (charindex(' ', AddressBlock) + 1), len(AddressBlock))) - 1)
ELSE substring(AddressBlock, (charindex(' ', AddressBlock) + 1), len(AddressBlock))
END AS 'Address 1',
CASE WHEN charindex(' ', substring(AddressBlock, (charindex(' ', AddressBlock) + 1), len(AddressBlock))) > 0 THEN substring(AddressBlock, charindex(' ', AddressBlock) + charindex(' ', substring(AddressBlock, (charindex(' ', AddressBlock) + 1), len(AddressBlock))) + 1, Len(AddressBlock))
ELSE ''
END AS 'Address 2'
Here is my version of the answer. This is MUCH faster and robust. No need to fuss around with substrings, charindex, etc.
CREATE FUNCTION [dbo].[SplitArray]
(
#RowToSplit nvarchar(MAX),
#Delimeter nvarchar(MAX)
)
RETURNS #RtnValue table (ID bigint IDENTITY, Data nvarchar(MAX))
AS
BEGIN
DECLARE #xml xml
SET #xml = '<field>' + REPLACE(#RowToSplit, #Delimeter, '</field><field>') + '</field>'
INSERT INTO #RtnValue(data)
SELECT tbl.c.value('.','nvarchar(max)')
FROM #xml.nodes('/field') tbl(c)
RETURN
END
You would simply use the resultant split values in a table, like this:
SELECT Data FROM dbo.SplitArray('this is great',' ')
This will return:
Data
============
this
is
great