Extract value in between string in SQL - sql

I have a sample string like below and this string always contains the word "Inventory Charge[0.00068]"
DECLARE #Text NVARCHAR(MAX) = 'Materials Discount[0] ) + Inventory Charge[0.00068] Second gfggfdgfd gfgfgfgf'
would like to get value in between brackets for Inventory Charge.
Required output: 0.00068
I have tried with substring but not able to get the desired result. Please help.
DECLARE #Text NVARCHAR(MAX) = 'Materials Discount[0] ) + Inventory Charge[0.00068] Second'
SELECT SUBSTRING(#Text, CHARINDEX('Inventory Charge[', #Text) +
LEN('Inventory Charge[') + 1, CHARINDEX(']',#Text)
- (CHARINDEX('Inventory Charge[', #Text) + 2 + LEN('Inventory Charge[')) )

I find this type of thing easier to work out when breaking it down. It also helps avoid repeating the initial search for the starting substring location:
declare #text NVARCHAR(MAX) = 'Materials Discount[0] ) + Inventory Charge[0.00068] Second'
declare #leftSearchStr nvarchar(20) = 'Inventory Charge['
declare #rightSearchStr nvarchar(20) = ']'
declare #startPos int = charindex(#leftSearchStr, #text, 1) + LEN(#leftSearchStr)
declare #endPos int = charindex(#rightSearchStr, #text, #startPos)
SELECT SUBSTRING(#text, #startPos, #endPos - #startPos)

I solved it like this. Surely there is a better way to solve this, but this works.
DECLARE #Text NVARCHAR(MAX) = 'Materials Discount[0] ) + Inventory Charge[0.00068] Second',
#Trim1 NVARCHAR(MAX),
#Trim2 NVARCHAR(MAX)
SET #Trim1 = SUBSTRING(#Text, CHARINDEX('[', #Text) + 1,LEN(#Text))
SET #Trim2 = SUBSTRING(#Trim1, CHARINDEX('[', #Trim1) + 1, LEN(#Trim1))
SELECT LEFT(#Trim2, LEN(#Trim2) - CHARINDEX(']', #Trim2) - 3)

If you know that the string you want to select is the Last bracketed selection, then we can simply use REVERSE and then find the first bracketed value.
If you have to do this in a single operation, I find it easier to incorporate a CROSS APPLY to calculate the steps in between:
DECLARE #Text NVARCHAR(MAX) = 'Materials Discount[0] ) + Inventory Charge[0.00068] Second'
SELECT Reverse(SubString(RevText, [RLeft], [RRight]-[RLeft]))
FROM ( SELECT REVERSE(#Text) as RevText) text
OUTER APPLY (SELECT CHARINDEX(']', RevText) + 1 as [RLeft],
CHARINDEX('[', revText) as [RRight]) Calcs
If you don't know for sure that the search term is the first or last bracket, then we just need to search on the prefix first, and use that as the start location for the CharIndex function:
SELECT SubString([Text], [Left], [Right]-[Left])
FROM ( SELECT #Text as [Text], 'Inventory Charge[' as prefix ) inputs
OUTER APPLY (SELECT CHARINDEX(prefix, [Text]) + LEN(prefix) as [Left]) Calcs1
OUTER APPLY (SELECT CHARINDEX(']', [Text], [Left]) as [Right]) Calcs2
You can get a little bit fancy using STRING_SPLIT to tokenize the input for you too, note that you need to split by the close bracket so that the value and the field prefix are in the same result:
This solution uses REVERSE again because we know the token is at the end of the line, so we can use LEFT logic to save an index lookup
SELECT Reverse(LEFT(REVERSE(value), CHARINDEX('[', REVERSE(value))-1))
FROM String_Split(#Text, ']') s
WHERE s.value LIKE '%Inventory Charge%'
Or you can use SUBSTRING again:
SELECT SUBSTRING(value,[LEFT],[Length] - [Left] + 1)
FROM String_Split(#Text, ']') s
CROSS APPLY (SELECT CHARINDEX('[', value) + 1 as [LEFT], LEN(value) as [Length]) calcs
WHERE s.value LIKE '%Inventory Charge%'

Related

How to extract string from a text in SQL Server

I have texts like "DBName_TemplateDB_TESTDB01234_document" and "DBName_TemplateDB_TESTDB01234678_document". From both texts need to extract string between second underscore() and last underscore() like "TESTDB01234" and "TESTDB01234678".
Can you please help how to string in SQL Server using SUBSTRING and CHARINDEX?
Example:
Input Text: 'DBName_TemplateDB_TESTDB01234_document'
Output: TESTDB01234
Input Text: 'DBName_TemplateDB_TESTDB01234678_document'
Output: TESTDB01234678
I tried to extract and it's working only from the first underscore like below.
declare #Dbname varchar(max) = '#new#-TESTDB01234_document'
select substring( LEFT(#DbName,charindex('_',#DbName)-1),charindex('TEST',#DbName),len(LEFT(#DbName,charindex('_',#DbName)))-1)
Will this work for you?
--OPTION ONE: SUBSTRING
DECLARE #Start INT = CHARINDEX('TEST', #Dbname);
DECLARE #End INT = LEN(#Dbname) - (CHARINDEX('_', REVERSE(#Dbname)) - 1) - #Start;
SELECT SUBSTRING(#Dbname, #Start, #End) AS [Name]
--OPTION TWO: DOUBLE REPLACE
SELECT REPLACE(REPLACE(#Dbname, 'DBName_TemplateDB_', ''), '_document', ''); AS [Name]
--OPTION THREE: STRING_SPLIT
SELECT TOP 1 value AS [Name]
FROM STRING_SPLIT(#Dbname, '_')
WHERE value LIKE 'Test%'
I added a few options, sorry if its outside the scope of the question.
Using charindex
declare #Dbname varchar(max) = 'DBName_TemplateDB_TESTDB01234678_document'
select right(left(#DbName,third - 1), third - second - 1)
from (
select charindex('_',#DbName,charindex('_',#DbName) + 1) second,
charindex('_',#DbName,charindex('_',#DbName,charindex('_',#DbName) + 1) + 1) third
) t
If you are looking for data between the second and the last underscore, I will give the following approach as there might be more underscores between these ones:
declare #Dbname varchar(max) = 'DBName_TemplateDB_TESTDB01234678_1_2_3_document'
DECLARE #DbnameXML XML = '<a>' + REPLACE(#Dbname, '_', '</a><a>') + '</a>';
SELECT STRING_AGG([value], '_') WITHIN GROUP (ORDER BY [value_id])
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY T.c) - 1
,T.c.value('.', 'VARCHAR(128)')
,COUNT(1) OVER()
FROM #DbnameXML.nodes('a') T(c)
) DS ([value_id], [value], [values_count])
WHERE [value_id] > 1
AND [value_id] + 1 < [values_count]

Get substring between second and fourth slash

I have a string that looks like this:
Y:\Data\apples\oranges\Scott\notes
I need a column that looks like this:
apples\oranges
This is what I have so far and it does not work:
SELECT SUBSTRING(
[Group],
CHARINDEX('\', [Group]) + 1,
LEN([Group]) - CHARINDEX('\', [Group]) - CHARINDEX('\', REVERSE([Group]))
) from datamap.finaltest
The strings will not always have a finite amount of slashes. For example you could have:
Y:\Data\Apples\bananas
Y:\Apples\Pears\oranges\peanuts
The data will always have:
drive letter + '\' + '1st level folder' + '\' + 'Second level folder'
It may have more than two levels though.
I have searched the forum but can't find anything specific.
Thanks
A blatant approach by converting your input into XML and taking the values by node and re-concatenating the nodes you want in output
;WITH MyTempData
AS
(
SELECT Convert(xml,'<n>'+Replace('Y:\Data\Apples','\','</n><n>')+'</n>') XMLString
)
SELECT COALESCE(XMLString.value('(/n[3])', 'varchar(20)'),'') + '\' +
COALESCE(XMLString.value('(/n[4])', 'varchar(20)'),'') MyFinalOutput
FROM MyTempData
Probably not the best way, but this will get you there.
DECLARE #string varchar(255) = 'Y:\data\apples\oranges\Scott\notes'
SELECT LEFT(RIGHT(#string,LEN(#string)-CHARINDEX('\', #string, CHARINDEX('\', #string,1) + 1)),CHARINDEX('\', RIGHT(#string,LEN(#string)-CHARINDEX('\', #string, CHARINDEX('\', #string,1) + 1)), CHARINDEX('\',RIGHT(#string,LEN(#string)-CHARINDEX('\', #string, CHARINDEX('\', #string,1) + 1)),1)+1)-1)
Here is a way using recursive CHARINDEX
declare #var varchar(4000) = 'Y:\Data\apples\oranges\Scott\notes'
declare #firstSlash int = (select CHARINDEX('\',#var,CHARINDEX('\',#var) + 1))
declare #fourthSlash int = (select CHARINDEX('\',#var,CHARINDEX('\',#var,CHARINDEX('\',#var,CHARINDEX('\',#var) + 1)+1)+1))
select SUBSTRING(#var,#firstSlash + 1,#fourthSlash - #firstSlash - 1)
Or, for your data table...
select SUBSTRING([Group],CHARINDEX('\',[Group],CHARINDEX('\',[Group]) + 1) + 1,CHARINDEX('\',[Group],CHARINDEX('\',[Group],CHARINDEX('\',[Group],CHARINDEX('\',[Group]) + 1)+1)+1) - CHARINDEX('\',[Group],CHARINDEX('\',[Group]) + 1) - 1)
If this is something you need to do often, or is prone to changing, it may be beneficial to implement a function which will make your code more readable/maintainable:
SELECT SUBSTRING(#t, dbo.CHARINDEX2('\', #t, 2) + 1, dbo.CHARINDEX2('\', #t, 3));
Using this 'find nth occurence' function:
http://www.sqlservercentral.com/scripts/Miscellaneous/30497/

How to use substring conditionally before and after two different symbols in SQL SERVER

I have a table A with ID col. Here is sample data -
ID
NT-QR-1499-1(2015)
NT-XYZ-1503-1
NT-RET-546-1(2014)
I need to select everything after first '-' from left and before '(' from the right. However, some records do not have '(', in which case, the second condition would not apply.
Here is what I need -
QR-1499-1
XYZ-1503-1
RET-546-1
You could get it done in a CASE statement, although I'd definitely take any advice from Aaron;
CREATE TABLE #TestData (ID nvarchar(50))
INSERT INTO #TestData (ID)
VALUES
('NT-QR-1499-1(2015)')
,('NT-XYZ-1503-1')
,('NT-RET-546-1(2014)')
SELECT
ID
,CASE
WHEN CHARINDEX('(',ID) = 0
THEN RIGHT(ID, LEN(ID)-CHARINDEX('-',ID))
ELSE LEFT(RIGHT(ID, LEN(ID)-CHARINDEX('-',ID)),CHARINDEX('(',RIGHT(ID, LEN(ID)-CHARINDEX('-',ID)))-1)
END Result
FROM #TestData
Try this:
SELECT y.i, SUBSTRING(ID, x.i + 1, IIF(y.i = 0, LEN(ID), y.i - x.i - 1))
FROM mytable
CROSS APPLY (SELECT CHARINDEX('-', ID)) AS x(i)
CROSS APPLY (SELECT CHARINDEX('(', ID)) AS y(i)
It looks like your column is not actually a single data element, but multiple data elements that have been concatenated together. A bad idea for database design, which is causing the problem that you're having now.
This should give you what you need, but strongly consider separating the column into the required pieces.
SELECT
SUBSTRING(id, CHARINDEX('-', id) + 1, LEN(id) - CHARINDEX('(', REVERSE(id)) - CHARINDEX('-', id))
FROM
My_Table
DECLARE #str varchar(64);
DECLARE #start int;
DECLARE #length int;
SELECT #str = 'NT-QR-1499-1(2015)';
/*SELECT #str = 'NT-XYZ-1503-1';*/
SELECT #start = CHARINDEX('-', #str) + 1;
SELECT #length = CHARINDEX('(', #str) - #start;
IF (#length > 0)
SELECT SUBSTRING(#str, #start, #length)
ELSE
SELECT SUBSTRING(#str, #start, LEN(#str))
GO
SELECT CASE
WHEN CHARINDEX('(',ID) > 0
THEN
SUBSTRING(ID,CHARINDEX('-',ID)+1,(CHARINDEX('(',ID)-CHARINDEX('-',ID)-1))
ELSE
SUBSTRING(ID,CHARINDEX('-',ID)+1)
END AS New_Column_Name
FROM Table_Name
First it will check whether "(" present or not .
If present then it will fetch the data from next position of "-" to before the position of "(".
otherwise it will fetch the data from next position of "-" to till end.

Get everything after and before certain character in SQL Server

I got the following entry in my database:
images/test.jpg
I want to trim the entry so I get: test
So basically, I want everything after / and before .
How can I solve it?
use the following function
left(#test, charindex('/', #test) - 1)
If you want to get this out of your table using SQL, take a look at the following functions that will help you: SUBSTRING and CHARINDEX. You can use those to trim your entries.
A possible query will look like this (where col is the name of the column that contains your image directories:
SELECT SUBSTRING(col, LEN(SUBSTRING(col, 0, LEN(col) - CHARINDEX ('/', col))) + 1,
LEN(col) - LEN(SUBSTRING(col, 0, LEN(col) - CHARINDEX ('/', col))) - LEN(SUBSTRING(
col, CHARINDEX ('.', col), LEN(col))));
Bit of an ugly beast. It also depends on the standard format of 'dir/name.ext'.
Edit:
This one (inspired by praveen) is more generic and deals with extensions of different length:
SELECT SUBSTRING(col, LEN(LEFT(col, CHARINDEX ('/', col))) + 1, LEN(col) - LEN(LEFT(col,
CHARINDEX ('/', col))) - LEN(RIGHT(col, LEN(col) - CHARINDEX ('.', col))) - 1);
Before
SELECT SUBSTRING(ParentBGBU,0,CHARINDEX('/',ParentBGBU,0)) FROM dbo.tblHCMMaster;
After
SELECT SUBSTRING(ParentBGBU,CHARINDEX('-',ParentBGBU)+1,LEN(ParentBGBU)) FROM dbo.tblHCMMaster
----select characters before / including /
select SUBSTRING ('abcde/wxyz',0,CHARINDEX('/','abcde/wxyz')+1)
--select characters after / including /
select SUBSTRING('abcde/wxyz',CHARINDEX('/','abcde/wxyz'),LEN('abcde/wxyz'))
declare #T table
(
Col varchar(20)
)
insert into #T
Select 'images/test1.jpg'
union all
Select 'images/test2.png'
union all
Select 'images/test3.jpg'
union all
Select 'images/test4.jpeg'
union all
Select 'images/test5.jpeg'
Select substring( LEFT(Col,charindex('.',Col)-1),charindex('/',Col)+1,len(LEFT(Col,charindex('.',Col)-1))-1 )
from #T
I have made a method which is much more general :
so :
DECLARE #a NVARCHAR(MAX)='images/test.jpg';
--Touch here
DECLARE #keysValueToSearch NVARCHAR(4000) = '/'
DECLARE #untilThisCharAppears NVARCHAR(4000) = '.'
DECLARE #keysValueToSearchPattern NVARCHAR(4000) = '%' + #keysValueToSearch + '%'
--Nothing to touch here
SELECT SUBSTRING(
#a,
PATINDEX(#keysValueToSearchPattern, #a) + LEN(#keysValueToSearch),
CHARINDEX(
#untilThisCharAppears,
#a,
PATINDEX(#keysValueToSearchPattern, #a) + LEN(#keysValueToSearch)
) -(PATINDEX(#keysValueToSearchPattern, #a) + LEN(#keysValueToSearch))
)
SELECT Substring('ravi1234#gmail.com', 1, ( Charindex('#', 'ravi1234#gmail.com')
- 1 ))
Before,
RIGHT('ravi123#gmail.com', ( Charindex('#', 'ravi123#gmail.com') + 1 ))
After
I just did this in one of my reports and it was very simple.
Try this:
=MID(Fields!.Value,8,4)
Note: This worked for me because the value I was trying to get was a constant not sure it what you are trying to get is a constant as well.
I know this has been a while.. but here is an idea
declare #test varchar(25) = 'images/test.jpg'
select
#test as column_name
, parsename(replace(#test,'/','.'),1) as jpg
,parsename(replace(#test,'/','.'),2) as test
,parsename(replace(#test,'/','.'),3) as images
I found Royi Namir's answer useful but expanded upon it to create it as a function. I renamed the variables to what made sense to me but you can translate them back easily enough, if desired.
Also, the code in Royi's answer already handled the case where the character being searched from does not exist (it starts from the beginning of the string), but I wanted to also handle cases where the character that is being searched to does not exist.
In that case it acts in a similar manner by starting from the searched from character and returning the rest of the characters to the end of the string.
CREATE FUNCTION [dbo].[getValueBetweenTwoStrings](#inputString
NVARCHAR(4000), #stringToSearchFrom NVARCHAR(4000), #stringToSearchTo
NVARCHAR(4000))
RETURNS NVARCHAR(4000)
AS
BEGIN
DECLARE #retVal NVARCHAR(4000)
DECLARE #stringToSearchFromSearchPattern NVARCHAR(4000) = '%' +
#stringToSearchFrom + '%'
SELECT #retVal = SUBSTRING (
#inputString,
PATINDEX(#stringToSearchFromSearchPattern, #inputString) + LEN(#stringToSearchFrom),
(CASE
CHARINDEX(
#stringToSearchTo,
#inputString,
PATINDEX(#stringToSearchFromSearchPattern, #inputString) + LEN(#stringToSearchFrom))
WHEN
0
THEN
LEN(#inputString) + 1
ELSE
CHARINDEX(
#stringToSearchTo,
#inputString,
PATINDEX(#stringToSearchFromSearchPattern, #inputString) + LEN(#stringToSearchFrom))
END) - (PATINDEX(#stringToSearchFromSearchPattern, #inputString) + LEN(#stringToSearchFrom))
)
RETURN #retVal
END
Usage:
SELECT dbo.getValueBetweenTwoStrings('images/test.jpg','/','.') AS MyResult
I got some invalid length errors. So i made this function, this should not give any length problems. Also when you do not find the searched text it will return a NULL.
CREATE FUNCTION [FN].[SearchTextGetBetweenStartAndStop](#string varchar(max),#SearchStringToStart varchar(max),#SearchStringToStop varchar(max))
RETURNS varchar(max)
BEGIN
SET #string = CASE
WHEN CHARINDEX(#SearchStringToStart,#string) = 0
OR CHARINDEX(#SearchStringToStop,RIGHT(#string,LEN(#string) - CHARINDEX(#SearchStringToStart,#string) + 1 - LEN(#SearchStringToStart))) = 0
THEN NULL
ELSE SUBSTRING(#string
,CHARINDEX(#SearchStringToStart,#string) + LEN(#SearchStringToStart) + 1
,(CHARINDEX(#SearchStringToStop,RIGHT(#string,LEN(#string) - CHARINDEX(#SearchStringToStart,#string) + 1 - LEN(#SearchStringToStart)))-2)
)
END
RETURN #string
END
if Input= pg102a-wlc01s.png.intel.com and Output should be pg102a-wlc01s
we can use below query :
select Substring(pc.name,0,charindex('.',pc.name,0)),pc.name from tbl_name pc
You can try this:
Declare #test varchar(100)='images/test.jpg'
Select REPLACE(RIGHT(#test,charindex('/',reverse(#test))-1),'.jpg','')
Below query gives you data before '-'
Ex- W12345A-4S
SELECT SUBSTRING(Column_Name,0, CHARINDEX('-',Column_Name)) as 'new_name'
from [abc].
Output - W12345A
Inspired by the work of Josien, I wondered about a simplification.
Would this also work? Much shorter:
SELECT SUBSTRING(col, CHARINDEX ('/', col) + 1, CHARINDEX ('.', col) - CHARINDEX ('/', col) - 1);
(I can't test right now because of right issues at my company SQL server, which is a problem in its own right)
Simply Try With LEFT ,RIGHT ,CHARINDEX
select
LEFT((RIGHT(a.name,((CHARINDEX('/', name))+1))),((CHARINDEX('.', (RIGHT(a.name,
((CHARINDEX('/', name))+1)))))-1)) splitstring,
a.name
from
(select 'images/test.jpg' as name)a
declare #searchStart nvarchar(100) = 'search ';
declare #searchEnd nvarchar(100) = ' ';
declare #string nvarchar(4000) = 'This is a string to search (hello) in this text ';
declare #startIndex int = CHARINDEX(#searchStart, #string,0) + LEN(#searchStart);
declare #endIndex int = CHARINDEX(#searchEnd, #string, #startIndex + 1);
declare #length int = #endIndex - #startIndex;
declare #sub nvarchar(4000) = SUBSTRING(#string, #startIndex, #length)
select #startIndex, #endIndex, #length, #sub
This is a little more legible than the one-liners in this answer which specifically answer the question, but not in a generic way that would benefit all readers. This could easily be made into a function as well with a slight modification.
If there are more than one or none occurences of given character use this:
DECLARE #rightidx int = CASE
WHEN 'images/images/test.jpg' IS NULL OR (CHARINDEX('.', 'images/images/test.jpg')) <= 0 THEN LEN('images/images/test.jpg')
ELSE (CHARINDEX('.', REVERSE('images/images/test.jpg')) - 1)
END
SELECT RIGHT('images/images/test.jpg', #rightidx)
This was the approach I took.
CREATE FUNCTION dbo.get_text_before_char(#my_string nvarchar(255),#my_char char(1))
RETURNS nvarchar(255)
AS
BEGIN;
return IIF(#my_string LIKE '%' + #my_char + '%',left (#my_string, IIF(charindex(#my_char, #my_string) - 1<1,1,charindex(#my_char, #my_string) - 1)),'');
END;
CREATE FUNCTION dbo.get_text_after_char(#my_string nvarchar(255),#my_char char(1))
RETURNS nvarchar(255)
AS
BEGIN;
return IIF ( #my_string LIKE '%' + #my_char + '%' ,RIGHT ( #my_string , IIF ( charindex ( #my_char ,reverse(#my_string) )-1 < 1 ,1 ,charindex ( #my_char ,reverse(#my_string) )-1 ) ) , '' )
END;
SELECT
dbo.get_text_before_char('foo-bar','-')
, dbo.get_text_after_char('foo-bar','-')
declare #test varchar(100)='images/test.jpg'
select right(left(#test, charindex('.', #test) - 1),4)

Using PATINDEX to find varying length patterns in T-SQL

I'm looking to pull floats out of some varchars, using PATINDEX() to spot them. I know in each varchar string, I'm only interested in the first float that exists, but they might have different lengths.
e.g.
'some text 456.09 other text'
'even more text 98273.453 la la la'
I would normally match these with a regex
"[0-9]+[.][0-9]+"
However, I can't find an equivalent for the + operator, which PATINDEX accepts. So they would need to be matched (respectively) with:
'[0-9][0-9][0-9].[0-9][0-9]' and '[0-9][0-9][0-9][0-9][0-9].[0-9][0-9][0-9]'
Is there any way to match both of these example varchars with one single valid PATINDEX pattern?
I blogged about this a while ago.
Extracting numbers with SQL server
Declare #Temp Table(Data VarChar(100))
Insert Into #Temp Values('some text 456.09 other text')
Insert Into #Temp Values('even more text 98273.453 la la la')
Insert Into #Temp Values('There are no numbers in this one')
Select Left(
SubString(Data, PatIndex('%[0-9.-]%', Data), 8000),
PatIndex('%[^0-9.-]%', SubString(Data, PatIndex('%[0-9.-]%', Data), 8000) + 'X')-1)
From #Temp
Wildcards.
SELECT PATINDEX('%[0-9]%[0-9].[0-9]%[0-9]%','some text 456.09 other text')
SELECT PATINDEX('%[0-9]%[0-9].[0-9]%[0-9]%','even more text 98273.453 la la la')
Yes you need to link to the clr to get regex support. But if PATINDEX does not do what you need then regex was designed exactly for that.
http://msdn.microsoft.com/en-us/magazine/cc163473.aspx
Should be checked for robustness (what if you only have an int, for example), but this is just to put you on a track:
if exists (select routine_name from information_schema.routines where routine_name = 'GetFirstFloat')
drop function GetFirstFloat
go
create function GetFirstFloat (#string varchar(max))
returns float
as
begin
declare #float varchar(max)
declare #pos int
select #pos = patindex('%[0-9]%', #string)
select #float = ''
while isnumeric(substring(#string, #pos, 1)) = 1
begin
select #float = #float + substring(#string, #pos, 1)
select #pos = #pos + 1
end
return cast(#float as float)
end
go
select dbo.GetFirstFloat('this is a string containing pi 3.14159216 and another non float 3 followed by a new fload 5.41 and that''s it')
select dbo.GetFirstFloat('this is a string with no float')
select dbo.GetFirstFloat('this is another string with an int 3')
Given that the pattern is going to be varied in length, you're not going to have a rough time getting this to work with PATINDEX. There is another post that I wrote, which I've modified to accomplish what you're trying to do here. Will this work for you?
CREATE TABLE #nums (n INT)
DECLARE #i INT
SET #i = 1
WHILE #i < 8000
BEGIN
INSERT #nums VALUES(#i)
SET #i = #i + 1
END
CREATE TABLE #tmp (
id INT IDENTITY(1,1) not null,
words VARCHAR(MAX) null
)
INSERT INTO #tmp
VALUES('I''m looking for a number, regardless of length, even 23.258 long'),('Maybe even pi which roughly 3.14159265358,'),('or possibly something else that isn''t a number')
UPDATE #tmp SET words = REPLACE(words, ',',' ')
;WITH CTE AS (SELECT ROW_NUMBER() OVER (ORDER BY ID) AS rownum, ID, NULLIF(SUBSTRING(' ' + words + ' ' , n , CHARINDEX(' ' , ' ' + words + ' ' , n) - n) , '') AS word
FROM #nums, #tmp
WHERE ID <= LEN(' ' + words + ' ') AND SUBSTRING(' ' + words + ' ' , n - 1, 1) = ' '
AND CHARINDEX(' ' , ' ' + words + ' ' , n) - n > 0),
ids AS (SELECT ID, MIN(rownum) AS rownum FROM CTE WHERE ISNUMERIC(word) = 1 GROUP BY id)
SELECT CTE.rownum, cte.id, cte.word
FROM CTE, ids WHERE cte.id = ids.id AND cte.rownum = ids.rownum
The explanation and origin of the code is covered in more detail in the origional post
PATINDEX is not powerful enough to do that. You should use regular expressions.
SQL Server has Regular expression support since SQL Server 2005.