Related
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;
In a procedure in SQL Server 2008 I need to replace a substring between 2 identifiers. I do not know the complete strings to be replaced, or if the second identifier exists.
If the terminator identifier is not present, I would need the end of the string to be considered one. Also, the identifiers could be the same.
DECLARE #startIdenfier VARCHAR(10) = 'the'
DECLARE #endIdenfier VARCHAR(10) = 'the'
DECLARE #newString VARCHAR(20) = 'new string that'
Sample input / output:
'This is the old string that the process needs to be applied on.' ->
'This is the new string that the process needs to be applied on.'
'This is the old string' ->
'This is the new string that'
SET #endIdenfier = 'I'
'This is the old string that I don't like' ->
'This is the new string that I don't like''
It is a generic replace and I havn't been able to find the proper way to do it, since the REPLACE function does not accept indexes.
EDIT: This community is awesome. I am sorry I cannot select multiple accepted solutions, but I thank you all for your help. I'll try all solutions already posted (besides the already accepted one which I tested) and up-vote individually.
--Find the start index plus the length of the string found (plus one for the space)
SET #startIdx = CHARINDEX(#startIdentifier, #initialString, 1) + LEN(#startIdentifier) + 1
--Find the next occurrence of the end identifier (minus one for the space)
SET #endIdx = CHARINDEX(#endIdentifier, #initialString, #startIdx) - 1;
--end not found?
IF #endIdx = -1 SET #endIdx = LEN(#initialString) + 1;
--Use the STUFF function to remove the old chars from endindex-startindex, and insert the new string at the startindex
SET #results = STUFF(#initialString, #startIdx, #endIdx - #startIdx, #newString)
In full:
DECLARE #startIdenfier Varchar(10)
SET #startIdenfier = 'the'
DECLARE #endIdenfier Varchar(10)
SET #endIdenfier = 'the'
DECLARE #newString Varchar(100)
SET #newString = 'new string that'
DECLARE #initialString VARCHAR(256) = 'this is the old string that the process needs to be applied on';
DECLARE #startIdx INT;
SET #startIdx = CHARINDEX(#startIdenfier, #initialString, 1) + LEN(#startIdenfier) + 1;
DECLARE #endIdx INT;
SET #endIdx= CHARINDEX(#endIdenfier, #initialString, #startIdx) - 1;
IF #endIdx = -1 SET #endIdx = LEN(#initialString) + 1;
DECLARE #results VARCHAR(256);
SET #results = STUFF(#initialString, #startIdx, #endIdx - #startIdx, #newString);
SELECT #results
You could do something like this:
/*Declare necessary variables*/
DECLARE #startIndex INT
DECLARE #endIndex INT
DECLARE #startReplace INT
DECLARE #lengthReplace INT
DECLARE #replaceString VARCHAR(500)
/*Get the index of the start/end idenfier*/
SELECT #startIndex = CHARINDEX ( #startIdenfier , #originalString)
SELECT #endIndex = CHARINDEX ( #startIdenfier , #originalString, #startIndex+1)
/*In case the end idenfier doesn't exist*/
IF #endIndex = 0
SET #endIndex = LEN(#originalString) + 1
SET #startReplace = #startIndex + len(#startIdenfier)
SET #lengthReplace = #endIndex - #startReplace
SELECT STUFF(#originalString, #startReplace, #lengthReplace, #newString)
I think you will need to incorporate the PATINDEX function and create the pattern by using your start and end identifiers. That will satisfy the condition where both start and end identifiers are present...
DECLARE #OldString nvarchar(max)
DECLARE #NewString nvarchar(max)
DECLARE #StartLocation bigint
DECLARE #Pattern nvarchar(200) = '%' + #StartIdentifier + ' % ' + #EndIdentifer + '%'
SELECT #StartLocation = PATINDEX(#Pattern, 'old complete string')
If the pattern is located, then you can get the string to be replaced by substringing the 'old complete string', starting at position (#StartLocation + Length of #StartIdentifier + 1). To determine the length for SUBSTRING, you need to locate the position of #EndIdentifier, using CHARINDEX of the old complete string beginning at ( #StartLocation + Length of #StartIdentifier + 1). Subtract ( #StartLocation + Length of StartIdentifier + 1) from result of CHARINDEX.
SELECT #OldString = SUBSTRING('complete old string', #StartLocation + LEN(#StartIdentifier) + 1, CHARINDEX(' ' + #EndIdentifier, 'old complete string', #StartLocation + LEN(#StartIdentifier) + 1) - (#StartLocation + LEN(#StartIdentifier) + 1)))
You can at this point do a straight forward REPLACE to get the new string.
SELECT #NewCompleteString = REPLACE('old complete string', #OldString, #NewString)
"If there is no 'terminator' identifier, I would need the end of the
string to be considered one."
If the initial pattern was not located, we fall back to search for the #StartIdentifier only. For this you can reset the pattern to contain the #StartIdentifier only...
SELECT #Pattern = '%' + #StartIdentifier + ' %'
SELECT #StartLocation = PATINDEX(#Pattern, 'old complete string')
If the pattern is located then you can get the old string to replace by SUBSTRING starting at ( #StartLocation + Length of #StartIdentifier + 1 ), with a length of 'old complete string' length - ( #StartLocation + Length of #StartIdentifier + 1 )...
SELECT #OldString = SUBSTRING('old complete string', #StartLocation + LEN(#StartIdentifier) + 1, LEN('old complete string') - (#StartLocation + LEN(#StartIdentifier) + 1))
You can then REPLACE...
SELECT #NewCompleteString = REPLACE('old complete string', #OldString, #NewString)
Something like this...
DECLARE #initialString VARCHAR(32) = '1234567890123456789'
DECLARE #startIdentifier VARCHAR(32) = '34'
DECLARE #endIdentifier VARCHAR(32) = '34'
DECLARE #newString VARCHAR(32) = 'ABC'
DECLARE #headChars INT = CHARINDEX(#startIdentifier, #initialString, 1)
IF #headChars > 0
SET #headChars = #headChars + LEN(#startIdentifier) - 1
DECLARE #bodyChars INT = CHARINDEX(#endIdentifier, #initialString, #headChars + 1)
IF #bodyChars > 0
SET #bodyChars = LEN(#initialString) - #bodyChars + 1
SELECT
LEFT(#initialString, #headChars)
+ #newString
+ RIGHT(#initialString, #bodyChars)
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=b8a179d0e63840dfa60905d9951e4b22
For example...
'1234567890123456789'
'34' => Start # 1 => Found # 3 => keep chars 1->4
'34' => Start # 5 => Found # 13 => keep chars 13->end
Just use STUFF and CHARINDEX. Figure out:
the position at which replacement begins (position of the + length of the)
the position at which replacement ends (position of the starting from see above)
And subtract the positions to calculate the number of characters to replace.
DECLARE #string VARCHAR(100) = 'This is the old string that the process needs to be applied on.'
DECLARE #replace VARCHAR(100) = 'NEW STRING THAT '
DECLARE #delim1 VARCHAR(100) = 'the '
DECLARE #delim2 VARCHAR(100) = 'the '
DECLARE #pos1 INT = CHARINDEX(#delim1, #string) + DATALENGTH(#delim1)
DECLARE #pos2 INT = ISNULL(NULLIF(CHARINDEX(#delim2, #string, #pos1), 0), DATALENGTH(#string) + 1)
SELECT STUFF(#string, #pos1, #pos2 - #pos1, #replace)
-- "This is the NEW STRING THAT the process needs to be applied on."
SET #delim2 = 'xxx'
SET #pos1 = CHARINDEX(#delim1, #string) + DATALENGTH(#delim1)
SET #pos2 = ISNULL(NULLIF(CHARINDEX(#delim2, #string, #pos1), 0), DATALENGTH(#string) + 1)
SELECT STUFF(#string, #pos1, #pos2 - #pos1, #replace)
-- "This is the NEW STRING THAT "
Note: spaces should be a part of search delimiters instead of the logic. the should not match them and threfore.
Here is the example which i want in output...
I have this input = "Automatic email sent"
But I want this output = "AutomaticEmailSent"
Thanks In Advance!
Use TextInfo.ToTitleCase
// Defines the string with mixed casing.
string myString = "Automatic email sent";
// Creates a TextInfo based on the "en-US" culture.
TextInfo myTI = new CultureInfo("en-US",false).TextInfo;
// Changes a string to titlecase, then replace the spaces with empty
string outputString = myTI.ToTitleCase(myString).Replace(" ", "");
Stealing a function from this answer which takes an text input and make it proper case (otherwise known as title case):
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);
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
Then you can combine this function with REPLACE:
SELECT REPLACE(dbo.ProperCase(column), ' ', '')
FROM MyTable
SQL Server
declare #value varchar(64) = rtrim(' ' + 'Automatic email sent')
;with t(n) as (
select n = charindex(' ', #value, 0)
union all
select n = charindex(' ', #value, n + 1)
from t
where n > 0
)
select #value = stuff(#value, n + 1, 1, upper(substring(#value, n + 1, 1))) from t where n > 0
select replace(#value, ' ', '')
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