I have a column in a table that has values like below and I'd like to get the numeric value after the keyword APP and before the next space after APP*
. Thanks so much in advance!
Data Service B2B **APP#1234** Rehearsal 03/01/2025
Office 365 **APP 23456** for project 123
Office 365 **APP555** for project 123
1234
23456
555
I am using the following function from this website: https://blog.sqlauthority.com/2008/10/14/sql-server-get-numeric-value-from-alpha-numeric-string-udf-for-get-numeric-numbers-only/
For #2 (Data Service B2B APP#1234 Rehearsal 03/01/2025
) above, it output 2 from B2B as well.
CREATE FUNCTION dbo.udf_GetNumeric
(@strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256)
AS
BEGIN
DECLARE @intAlpha INT
SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric)
BEGIN
WHILE @intAlpha > 0
BEGIN
SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric )
END
END
RETURN ISNULL(@strAlphaNumeric,0)
END
For a problem like this you want to avoid using a function (unless an iTVF) and certainly avoid using a loop, as neither perform very well.
This might not be the compact way to go about it, but the logic is clearer (IMO). You could move this into a function (iTVF) for reusability.
substring
from here to the next space.with TestValues as (
select *
from (
values
('Data Service B2B APP#1234 Rehearsal 03/01/2025'),
('Office 365 APP 23456 for project 123'),
('Office 365 APP555 for project 123')
) x (Value)
), cte1 as (
-- Find "APP" and remove from string
select Value
, substring(Value, patindex('%APP%', Value) + 3, len(Value)) NewValue
from TestValues
), cte2 as (
select Value
-- Find first numeric value after "APP"
, substring(NewValue, patindex('%[0-9]%', NewValue), len(NewValue)) NewNewValue
from cte1
)
select Value
-- Take a string until the next space
, substring(NewNewValue, 1, patindex('% %',NewNewValue)) Number
from cte2;
Returns
Value | Number |
---|---|
Data Service B2B APP#1234 Rehearsal 03/01/2025 | 1234 |
Office 365 APP 23456 for project 123 | 23456 |
Office 365 APP555 for project 123 | 555 |
A tidier solution is (Thanks for the reminder Martin Smith):
select Value, number
from (
values
('Data Service B2B APP#1234 Rehearsal 03/01/2025'),
('Office 365 APP 23456 for project 123'),
('Office 365 APP555 for project 123')
) TestValues (Value)
cross apply (values(substring(Value, patindex('%APP%', Value) + 3, len(Value)))) ca1 (substring_after_app)
cross apply (values(substring(substring_after_app, patindex('%[0-9]%', substring_after_app), len(substring_after_app)))) ca2 (substring_from_first_digit)
cross apply (values(substring(substring_from_first_digit, 1, patindex('% %',substring_from_first_digit)))) ca3 (number)
To run this against your own table use the following:
select Value, number
from MyTable
cross apply (values(substring(Value, patindex('%APP%', Value) + 3, len(Value)))) ca1 (substring_after_app)
cross apply (values(substring(substring_after_app, patindex('%[0-9]%', substring_after_app), len(substring_after_app)))) ca2 (substring_from_first_digit)
cross apply (values(substring(substring_from_first_digit, 1, patindex('% %',substring_from_first_digit)))) ca3 (number)