Trying to get all numerical values and periods form string











up vote
-1
down vote

favorite












There's data I'm trying to retrieve using a SELECT statement which is input by various people in regards to an amount in grams. As there doesnt seem to be a standard here are some of the ways people have written it:




  • 200g

  • 0.2KG

  • 0.200kg

  • 0.2

  • 0.2g(e)

  • 2KG

  • .222


I currently have this function below that returns all numerical characters into an NVARCHAR which I could then CONVERT into a decimal to use in calculations.



ALTER FUNCTION [dbo].[fn_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


This does work fine in some cases but, for an example, any data that's written like "0.2..." turns into a "2" which whilst working with grams and Kilograms isn't helpful.



I need it to output either to a DECIMAL or NVARCHAR and to keep the decimal place location so a 0.2 stays as a 0.2 and a 0.200 stays as such .



(letters are only ever at the start or end never inbetween the numbers, it does sometimes start with a .)










share|improve this question




















  • 1




    Are you really still using SQL Server 2005? It's way outside of support now. The better question, however, is why are you storing numerical data as a varchar and not as a numerical data type (even your function returns a varchar).
    – Larnu
    Nov 15 at 13:51












  • Its being transferred to 2012 very soon i believe, its not a server we use very often at all but yeah its an old one haha! Because when its originally stored that's just the format that is used, unfortunately i don't have any way to change that. It returns varchar because that's the datatype at the end, like i said, it doesnt create any bother with it staying like a varchar at all, thats not the issue.
    – A.Cassin
    Nov 15 at 13:58












  • But why was it originally stored as a varchar? As you're finding out, bad data type choices are always a problem. Unfortunately, any solutions I can think of would only work on SQL Server 2008+. Like I said, 2005 is way out of support now, so any upgrades should really have been completed already. Why are you only going to 2012 as well? That's out of support as well (it's only in extended). Only SQl Server 2014 - 2017 are fully supported at the moment.
    – Larnu
    Nov 15 at 14:01










  • Because originally we didnt have a need to manipulate the numbers. I believe it was an electronic form that only had a text field so when people entered in a number it was down to user preference on how they wrote it. Don't get me wrong, i know thats not a good way to have it at all, but this is what ive got to work with and i cant go thoruhg and manually change them all and then change the data type, theres way to much data to do that. I don't think its been fully decided as of yet what version we're moving to for that particular server, its not a decision i get to be involved in.
    – A.Cassin
    Nov 15 at 14:05










  • @A.Cassin you probably shouldn't migrate to 2012 as it's already out of mainstream support. Installing an old version doesn't mean you avoid bugs. It means you get all of the bugs that were fixed in later versions. And end up requiring a more expensive license too. Since 2016 SP1 features that were available only in Enterprise editions are available even in Express, including compression, in-memory tables, partitioning etc
    – Panagiotis Kanavos
    Nov 15 at 14:33

















up vote
-1
down vote

favorite












There's data I'm trying to retrieve using a SELECT statement which is input by various people in regards to an amount in grams. As there doesnt seem to be a standard here are some of the ways people have written it:




  • 200g

  • 0.2KG

  • 0.200kg

  • 0.2

  • 0.2g(e)

  • 2KG

  • .222


I currently have this function below that returns all numerical characters into an NVARCHAR which I could then CONVERT into a decimal to use in calculations.



ALTER FUNCTION [dbo].[fn_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


This does work fine in some cases but, for an example, any data that's written like "0.2..." turns into a "2" which whilst working with grams and Kilograms isn't helpful.



I need it to output either to a DECIMAL or NVARCHAR and to keep the decimal place location so a 0.2 stays as a 0.2 and a 0.200 stays as such .



(letters are only ever at the start or end never inbetween the numbers, it does sometimes start with a .)










share|improve this question




















  • 1




    Are you really still using SQL Server 2005? It's way outside of support now. The better question, however, is why are you storing numerical data as a varchar and not as a numerical data type (even your function returns a varchar).
    – Larnu
    Nov 15 at 13:51












  • Its being transferred to 2012 very soon i believe, its not a server we use very often at all but yeah its an old one haha! Because when its originally stored that's just the format that is used, unfortunately i don't have any way to change that. It returns varchar because that's the datatype at the end, like i said, it doesnt create any bother with it staying like a varchar at all, thats not the issue.
    – A.Cassin
    Nov 15 at 13:58












  • But why was it originally stored as a varchar? As you're finding out, bad data type choices are always a problem. Unfortunately, any solutions I can think of would only work on SQL Server 2008+. Like I said, 2005 is way out of support now, so any upgrades should really have been completed already. Why are you only going to 2012 as well? That's out of support as well (it's only in extended). Only SQl Server 2014 - 2017 are fully supported at the moment.
    – Larnu
    Nov 15 at 14:01










  • Because originally we didnt have a need to manipulate the numbers. I believe it was an electronic form that only had a text field so when people entered in a number it was down to user preference on how they wrote it. Don't get me wrong, i know thats not a good way to have it at all, but this is what ive got to work with and i cant go thoruhg and manually change them all and then change the data type, theres way to much data to do that. I don't think its been fully decided as of yet what version we're moving to for that particular server, its not a decision i get to be involved in.
    – A.Cassin
    Nov 15 at 14:05










  • @A.Cassin you probably shouldn't migrate to 2012 as it's already out of mainstream support. Installing an old version doesn't mean you avoid bugs. It means you get all of the bugs that were fixed in later versions. And end up requiring a more expensive license too. Since 2016 SP1 features that were available only in Enterprise editions are available even in Express, including compression, in-memory tables, partitioning etc
    – Panagiotis Kanavos
    Nov 15 at 14:33















up vote
-1
down vote

favorite









up vote
-1
down vote

favorite











There's data I'm trying to retrieve using a SELECT statement which is input by various people in regards to an amount in grams. As there doesnt seem to be a standard here are some of the ways people have written it:




  • 200g

  • 0.2KG

  • 0.200kg

  • 0.2

  • 0.2g(e)

  • 2KG

  • .222


I currently have this function below that returns all numerical characters into an NVARCHAR which I could then CONVERT into a decimal to use in calculations.



ALTER FUNCTION [dbo].[fn_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


This does work fine in some cases but, for an example, any data that's written like "0.2..." turns into a "2" which whilst working with grams and Kilograms isn't helpful.



I need it to output either to a DECIMAL or NVARCHAR and to keep the decimal place location so a 0.2 stays as a 0.2 and a 0.200 stays as such .



(letters are only ever at the start or end never inbetween the numbers, it does sometimes start with a .)










share|improve this question















There's data I'm trying to retrieve using a SELECT statement which is input by various people in regards to an amount in grams. As there doesnt seem to be a standard here are some of the ways people have written it:




  • 200g

  • 0.2KG

  • 0.200kg

  • 0.2

  • 0.2g(e)

  • 2KG

  • .222


I currently have this function below that returns all numerical characters into an NVARCHAR which I could then CONVERT into a decimal to use in calculations.



ALTER FUNCTION [dbo].[fn_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


This does work fine in some cases but, for an example, any data that's written like "0.2..." turns into a "2" which whilst working with grams and Kilograms isn't helpful.



I need it to output either to a DECIMAL or NVARCHAR and to keep the decimal place location so a 0.2 stays as a 0.2 and a 0.200 stays as such .



(letters are only ever at the start or end never inbetween the numbers, it does sometimes start with a .)







sql-server string tsql sql-server-2005






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 20 at 10:21









Salman A

174k66334421




174k66334421










asked Nov 15 at 13:45









A.Cassin

195




195








  • 1




    Are you really still using SQL Server 2005? It's way outside of support now. The better question, however, is why are you storing numerical data as a varchar and not as a numerical data type (even your function returns a varchar).
    – Larnu
    Nov 15 at 13:51












  • Its being transferred to 2012 very soon i believe, its not a server we use very often at all but yeah its an old one haha! Because when its originally stored that's just the format that is used, unfortunately i don't have any way to change that. It returns varchar because that's the datatype at the end, like i said, it doesnt create any bother with it staying like a varchar at all, thats not the issue.
    – A.Cassin
    Nov 15 at 13:58












  • But why was it originally stored as a varchar? As you're finding out, bad data type choices are always a problem. Unfortunately, any solutions I can think of would only work on SQL Server 2008+. Like I said, 2005 is way out of support now, so any upgrades should really have been completed already. Why are you only going to 2012 as well? That's out of support as well (it's only in extended). Only SQl Server 2014 - 2017 are fully supported at the moment.
    – Larnu
    Nov 15 at 14:01










  • Because originally we didnt have a need to manipulate the numbers. I believe it was an electronic form that only had a text field so when people entered in a number it was down to user preference on how they wrote it. Don't get me wrong, i know thats not a good way to have it at all, but this is what ive got to work with and i cant go thoruhg and manually change them all and then change the data type, theres way to much data to do that. I don't think its been fully decided as of yet what version we're moving to for that particular server, its not a decision i get to be involved in.
    – A.Cassin
    Nov 15 at 14:05










  • @A.Cassin you probably shouldn't migrate to 2012 as it's already out of mainstream support. Installing an old version doesn't mean you avoid bugs. It means you get all of the bugs that were fixed in later versions. And end up requiring a more expensive license too. Since 2016 SP1 features that were available only in Enterprise editions are available even in Express, including compression, in-memory tables, partitioning etc
    – Panagiotis Kanavos
    Nov 15 at 14:33
















  • 1




    Are you really still using SQL Server 2005? It's way outside of support now. The better question, however, is why are you storing numerical data as a varchar and not as a numerical data type (even your function returns a varchar).
    – Larnu
    Nov 15 at 13:51












  • Its being transferred to 2012 very soon i believe, its not a server we use very often at all but yeah its an old one haha! Because when its originally stored that's just the format that is used, unfortunately i don't have any way to change that. It returns varchar because that's the datatype at the end, like i said, it doesnt create any bother with it staying like a varchar at all, thats not the issue.
    – A.Cassin
    Nov 15 at 13:58












  • But why was it originally stored as a varchar? As you're finding out, bad data type choices are always a problem. Unfortunately, any solutions I can think of would only work on SQL Server 2008+. Like I said, 2005 is way out of support now, so any upgrades should really have been completed already. Why are you only going to 2012 as well? That's out of support as well (it's only in extended). Only SQl Server 2014 - 2017 are fully supported at the moment.
    – Larnu
    Nov 15 at 14:01










  • Because originally we didnt have a need to manipulate the numbers. I believe it was an electronic form that only had a text field so when people entered in a number it was down to user preference on how they wrote it. Don't get me wrong, i know thats not a good way to have it at all, but this is what ive got to work with and i cant go thoruhg and manually change them all and then change the data type, theres way to much data to do that. I don't think its been fully decided as of yet what version we're moving to for that particular server, its not a decision i get to be involved in.
    – A.Cassin
    Nov 15 at 14:05










  • @A.Cassin you probably shouldn't migrate to 2012 as it's already out of mainstream support. Installing an old version doesn't mean you avoid bugs. It means you get all of the bugs that were fixed in later versions. And end up requiring a more expensive license too. Since 2016 SP1 features that were available only in Enterprise editions are available even in Express, including compression, in-memory tables, partitioning etc
    – Panagiotis Kanavos
    Nov 15 at 14:33










1




1




Are you really still using SQL Server 2005? It's way outside of support now. The better question, however, is why are you storing numerical data as a varchar and not as a numerical data type (even your function returns a varchar).
– Larnu
Nov 15 at 13:51






Are you really still using SQL Server 2005? It's way outside of support now. The better question, however, is why are you storing numerical data as a varchar and not as a numerical data type (even your function returns a varchar).
– Larnu
Nov 15 at 13:51














Its being transferred to 2012 very soon i believe, its not a server we use very often at all but yeah its an old one haha! Because when its originally stored that's just the format that is used, unfortunately i don't have any way to change that. It returns varchar because that's the datatype at the end, like i said, it doesnt create any bother with it staying like a varchar at all, thats not the issue.
– A.Cassin
Nov 15 at 13:58






Its being transferred to 2012 very soon i believe, its not a server we use very often at all but yeah its an old one haha! Because when its originally stored that's just the format that is used, unfortunately i don't have any way to change that. It returns varchar because that's the datatype at the end, like i said, it doesnt create any bother with it staying like a varchar at all, thats not the issue.
– A.Cassin
Nov 15 at 13:58














But why was it originally stored as a varchar? As you're finding out, bad data type choices are always a problem. Unfortunately, any solutions I can think of would only work on SQL Server 2008+. Like I said, 2005 is way out of support now, so any upgrades should really have been completed already. Why are you only going to 2012 as well? That's out of support as well (it's only in extended). Only SQl Server 2014 - 2017 are fully supported at the moment.
– Larnu
Nov 15 at 14:01




But why was it originally stored as a varchar? As you're finding out, bad data type choices are always a problem. Unfortunately, any solutions I can think of would only work on SQL Server 2008+. Like I said, 2005 is way out of support now, so any upgrades should really have been completed already. Why are you only going to 2012 as well? That's out of support as well (it's only in extended). Only SQl Server 2014 - 2017 are fully supported at the moment.
– Larnu
Nov 15 at 14:01












Because originally we didnt have a need to manipulate the numbers. I believe it was an electronic form that only had a text field so when people entered in a number it was down to user preference on how they wrote it. Don't get me wrong, i know thats not a good way to have it at all, but this is what ive got to work with and i cant go thoruhg and manually change them all and then change the data type, theres way to much data to do that. I don't think its been fully decided as of yet what version we're moving to for that particular server, its not a decision i get to be involved in.
– A.Cassin
Nov 15 at 14:05




Because originally we didnt have a need to manipulate the numbers. I believe it was an electronic form that only had a text field so when people entered in a number it was down to user preference on how they wrote it. Don't get me wrong, i know thats not a good way to have it at all, but this is what ive got to work with and i cant go thoruhg and manually change them all and then change the data type, theres way to much data to do that. I don't think its been fully decided as of yet what version we're moving to for that particular server, its not a decision i get to be involved in.
– A.Cassin
Nov 15 at 14:05












@A.Cassin you probably shouldn't migrate to 2012 as it's already out of mainstream support. Installing an old version doesn't mean you avoid bugs. It means you get all of the bugs that were fixed in later versions. And end up requiring a more expensive license too. Since 2016 SP1 features that were available only in Enterprise editions are available even in Express, including compression, in-memory tables, partitioning etc
– Panagiotis Kanavos
Nov 15 at 14:33






@A.Cassin you probably shouldn't migrate to 2012 as it's already out of mainstream support. Installing an old version doesn't mean you avoid bugs. It means you get all of the bugs that were fixed in later versions. And end up requiring a more expensive license too. Since 2016 SP1 features that were available only in Enterprise editions are available even in Express, including compression, in-memory tables, partitioning etc
– Panagiotis Kanavos
Nov 15 at 14:33














3 Answers
3






active

oldest

votes

















up vote
0
down vote



accepted










You can find some char that is not used, and replace .0 with it. Then put it back:



 BEGIN

DECLARE @intAlpha INT

SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '.0', '#');
SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '0.', '##');
SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '.', '###');

SET @intAlpha = PATINDEX('%[^0-9#]%', @strAlphaNumeric)

WHILE @intAlpha > 0
BEGIN
SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
SET @intAlpha = PATINDEX('%[^0-9#]%', @strAlphaNumeric )
END

SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '###', '.')
SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '##', '0.');
SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '#', '.0');

SELECT ISNULL(@strAlphaNumeric,0)
END


or just add the . like this:



PATINDEX('%[^0-9.]%', @strAlphaNumeric)


but you will have issue if you have string like this: te....st 5.0 kg, so it will be better just to replace .0 with something special.



Note, in the example I am replacing with # but you can replace with five of them in order to make the value more unique - #####, for example.






share|improve this answer






























    up vote
    0
    down vote













    String parsing in T-SQL is always challenging. But with this situation, SUBSTRING might be easier.



    You mentioned this: letters are only ever at the start or end never inbetween the numbers



    So basically we just need to find where the number starts and ends in the string.



    Have a look at this:



    DECLARE @String NVARCHAR(100)

    SET @String = 'This is k.g. or g it''s .0456 not g'

    SELECT PATINDEX('%[0-9 ].%[0-9]%', @String ) --Where is the first occurance of a number
    SELECT PATINDEX('%[0-9]%', REVERSE(@String)) --Flip the string and tell me from the other end where that number occurs
    SELECT LEN(@String) - PATINDEX('%[0-9 ].%[0-9]%', REVERSE(@String)) - PATINDEX('%[0-9]%', @String ) +2 --substract those from the length and add 2, tells me how long it is.

    --The above is basically where the number starts and it's length in the string.
    --Then use substring to pull it all out.
    SELECT SUBSTRING(@String, PATINDEX('%[0-9 ].%[0-9]%', @String ), LEN(@String) - PATINDEX('%[0-9]%', REVERSE(@String)) - PATINDEX('%[0-9 ].%[0-9]%', @String ) +2)

    --larger sample set
    IF OBJECT_ID('tempdb..#TestData') IS NOT NULL
    DROP TABLE #TestData

    CREATE TABLE #TestData (
    NumberData NVARCHAR(100)
    )

    INSERT INTO #TestData (
    [NumberData]
    )
    VALUES
    ('200g')
    ,('0.2KG')
    ,('0.200kg')
    ,('0.2')
    ,('0.2g(e)')
    ,('0.2000000k.g.')
    ,('grams 0.345')
    ,('This is k.g. 0.456 not g')
    ,('.456kg')

    SELECT *, SUBSTRING([NumberData], PATINDEX('%[0-9 ].%[0-9]%', [NumberData] ), LEN([NumberData]) - PATINDEX('%[0-9]%', REVERSE([NumberData])) - PATINDEX('%[0-9 ].%[0-9]%', [NumberData] ) +2)FROM #TestData





    share|improve this answer























    • Not entirely sure, but its having an issue running that. Say's theres incorrect syntax at the location ,('0.2KG')
      – A.Cassin
      Nov 15 at 15:40










    • @A.Cassin Sorry I don't see it. I just copied and pasted my example back out and ran it with no error.
      – Tim Mylott
      Nov 15 at 16:17












    • @A.Cassin oh wait, my bad, you're 2005 and this example is using a table variable which wasn't until 2008. I'll update so have a working example.
      – Tim Mylott
      Nov 15 at 16:21


















    up vote
    0
    down vote













    You need to include . as part of a number. Rest is somewhat straight forward as long as there is a valid number present in the string after the first numeric character:



    DECLARE @t TABLE (test VARCHAR(256));
    INSERT INTO @t VALUES
    ('200g'),
    ('0.2kg'),
    ('0.200kg'),
    ('0.2g(e)'),
    ('0.2'),
    ('.2'),
    ('2KG'),
    ('2'),
    ('foo200bar'),
    ('foobar');

    SELECT *, CAST(substr2 AS DECIMAL(10, 4)) AS result
    FROM @t
    CROSS APPLY (SELECT PATINDEX('%[.0-9]%', test) AS pos1) AS ca1
    CROSS APPLY (SELECT CASE WHEN pos1 = 0 THEN NULL ELSE SUBSTRING(test, pos1, LEN(test) - pos1 + 1) END AS substr1) AS ca2
    CROSS APPLY (SELECT PATINDEX('%[^.0-9]%', substr1) AS pos2) AS ca3
    CROSS APPLY (SELECT CASE WHEN pos2 = 0 THEN substr1 ELSE SUBSTRING(substr1, 1, pos2 - 1) END AS substr2) AS ca4


    Demo on DB Fiddle



    Converted to function:



    CREATE FUNCTION dbo.fn_GetNumeric(@test VARCHAR(256)) RETURNS DECIMAL(10, 4) AS
    BEGIN
    DECLARE @pos1 AS INT = PATINDEX('%[.0-9]%', @test);
    IF @pos1 = 0 RETURN NULL;

    DECLARE @substr AS VARCHAR(256) = SUBSTRING(@test, @pos1, LEN(@test) - @pos1 + 1);

    DECLARE @pos2 AS INT = PATINDEX('%[^.0-9]%', @substr);
    IF @pos2 = 0 RETURN @substr;

    RETURN SUBSTRING(@substr, 1, @pos2 - 1);
    END


    Demo on DB Fiddle






    share|improve this answer























    • I'm sorry, i hadn't realised i didn't put that there can also be a condiiton where the data is written like 2KG so if that needs a valid number after the first, it will fail, correct?
      – A.Cassin
      Nov 15 at 14:55










    • 2KG becomes decimal 2.0000.
      – Salman A
      Nov 15 at 14:58












    • Hmm, Would you be able to rearrange this so it would work in a function at all that returns a value?
      – A.Cassin
      Nov 15 at 15:16










    • @A.Cassin see dbfiddle.uk/…
      – Salman A
      Nov 15 at 15:27










    • Ive seen that it only has a dropdown for 2012 as the oldest... Would you know that this would work in 2005? (i know its old)
      – A.Cassin
      Nov 15 at 15:36











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53320847%2ftrying-to-get-all-numerical-values-and-periods-form-string%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    0
    down vote



    accepted










    You can find some char that is not used, and replace .0 with it. Then put it back:



     BEGIN

    DECLARE @intAlpha INT

    SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '.0', '#');
    SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '0.', '##');
    SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '.', '###');

    SET @intAlpha = PATINDEX('%[^0-9#]%', @strAlphaNumeric)

    WHILE @intAlpha > 0
    BEGIN
    SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
    SET @intAlpha = PATINDEX('%[^0-9#]%', @strAlphaNumeric )
    END

    SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '###', '.')
    SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '##', '0.');
    SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '#', '.0');

    SELECT ISNULL(@strAlphaNumeric,0)
    END


    or just add the . like this:



    PATINDEX('%[^0-9.]%', @strAlphaNumeric)


    but you will have issue if you have string like this: te....st 5.0 kg, so it will be better just to replace .0 with something special.



    Note, in the example I am replacing with # but you can replace with five of them in order to make the value more unique - #####, for example.






    share|improve this answer



























      up vote
      0
      down vote



      accepted










      You can find some char that is not used, and replace .0 with it. Then put it back:



       BEGIN

      DECLARE @intAlpha INT

      SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '.0', '#');
      SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '0.', '##');
      SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '.', '###');

      SET @intAlpha = PATINDEX('%[^0-9#]%', @strAlphaNumeric)

      WHILE @intAlpha > 0
      BEGIN
      SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
      SET @intAlpha = PATINDEX('%[^0-9#]%', @strAlphaNumeric )
      END

      SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '###', '.')
      SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '##', '0.');
      SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '#', '.0');

      SELECT ISNULL(@strAlphaNumeric,0)
      END


      or just add the . like this:



      PATINDEX('%[^0-9.]%', @strAlphaNumeric)


      but you will have issue if you have string like this: te....st 5.0 kg, so it will be better just to replace .0 with something special.



      Note, in the example I am replacing with # but you can replace with five of them in order to make the value more unique - #####, for example.






      share|improve this answer

























        up vote
        0
        down vote



        accepted







        up vote
        0
        down vote



        accepted






        You can find some char that is not used, and replace .0 with it. Then put it back:



         BEGIN

        DECLARE @intAlpha INT

        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '.0', '#');
        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '0.', '##');
        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '.', '###');

        SET @intAlpha = PATINDEX('%[^0-9#]%', @strAlphaNumeric)

        WHILE @intAlpha > 0
        BEGIN
        SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
        SET @intAlpha = PATINDEX('%[^0-9#]%', @strAlphaNumeric )
        END

        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '###', '.')
        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '##', '0.');
        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '#', '.0');

        SELECT ISNULL(@strAlphaNumeric,0)
        END


        or just add the . like this:



        PATINDEX('%[^0-9.]%', @strAlphaNumeric)


        but you will have issue if you have string like this: te....st 5.0 kg, so it will be better just to replace .0 with something special.



        Note, in the example I am replacing with # but you can replace with five of them in order to make the value more unique - #####, for example.






        share|improve this answer














        You can find some char that is not used, and replace .0 with it. Then put it back:



         BEGIN

        DECLARE @intAlpha INT

        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '.0', '#');
        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '0.', '##');
        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '.', '###');

        SET @intAlpha = PATINDEX('%[^0-9#]%', @strAlphaNumeric)

        WHILE @intAlpha > 0
        BEGIN
        SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
        SET @intAlpha = PATINDEX('%[^0-9#]%', @strAlphaNumeric )
        END

        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '###', '.')
        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '##', '0.');
        SET @strAlphaNumeric = REPLACE(@strAlphaNumeric, '#', '.0');

        SELECT ISNULL(@strAlphaNumeric,0)
        END


        or just add the . like this:



        PATINDEX('%[^0-9.]%', @strAlphaNumeric)


        but you will have issue if you have string like this: te....st 5.0 kg, so it will be better just to replace .0 with something special.



        Note, in the example I am replacing with # but you can replace with five of them in order to make the value more unique - #####, for example.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 15 at 14:34

























        answered Nov 15 at 14:02









        gotqn

        19.4k32110189




        19.4k32110189
























            up vote
            0
            down vote













            String parsing in T-SQL is always challenging. But with this situation, SUBSTRING might be easier.



            You mentioned this: letters are only ever at the start or end never inbetween the numbers



            So basically we just need to find where the number starts and ends in the string.



            Have a look at this:



            DECLARE @String NVARCHAR(100)

            SET @String = 'This is k.g. or g it''s .0456 not g'

            SELECT PATINDEX('%[0-9 ].%[0-9]%', @String ) --Where is the first occurance of a number
            SELECT PATINDEX('%[0-9]%', REVERSE(@String)) --Flip the string and tell me from the other end where that number occurs
            SELECT LEN(@String) - PATINDEX('%[0-9 ].%[0-9]%', REVERSE(@String)) - PATINDEX('%[0-9]%', @String ) +2 --substract those from the length and add 2, tells me how long it is.

            --The above is basically where the number starts and it's length in the string.
            --Then use substring to pull it all out.
            SELECT SUBSTRING(@String, PATINDEX('%[0-9 ].%[0-9]%', @String ), LEN(@String) - PATINDEX('%[0-9]%', REVERSE(@String)) - PATINDEX('%[0-9 ].%[0-9]%', @String ) +2)

            --larger sample set
            IF OBJECT_ID('tempdb..#TestData') IS NOT NULL
            DROP TABLE #TestData

            CREATE TABLE #TestData (
            NumberData NVARCHAR(100)
            )

            INSERT INTO #TestData (
            [NumberData]
            )
            VALUES
            ('200g')
            ,('0.2KG')
            ,('0.200kg')
            ,('0.2')
            ,('0.2g(e)')
            ,('0.2000000k.g.')
            ,('grams 0.345')
            ,('This is k.g. 0.456 not g')
            ,('.456kg')

            SELECT *, SUBSTRING([NumberData], PATINDEX('%[0-9 ].%[0-9]%', [NumberData] ), LEN([NumberData]) - PATINDEX('%[0-9]%', REVERSE([NumberData])) - PATINDEX('%[0-9 ].%[0-9]%', [NumberData] ) +2)FROM #TestData





            share|improve this answer























            • Not entirely sure, but its having an issue running that. Say's theres incorrect syntax at the location ,('0.2KG')
              – A.Cassin
              Nov 15 at 15:40










            • @A.Cassin Sorry I don't see it. I just copied and pasted my example back out and ran it with no error.
              – Tim Mylott
              Nov 15 at 16:17












            • @A.Cassin oh wait, my bad, you're 2005 and this example is using a table variable which wasn't until 2008. I'll update so have a working example.
              – Tim Mylott
              Nov 15 at 16:21















            up vote
            0
            down vote













            String parsing in T-SQL is always challenging. But with this situation, SUBSTRING might be easier.



            You mentioned this: letters are only ever at the start or end never inbetween the numbers



            So basically we just need to find where the number starts and ends in the string.



            Have a look at this:



            DECLARE @String NVARCHAR(100)

            SET @String = 'This is k.g. or g it''s .0456 not g'

            SELECT PATINDEX('%[0-9 ].%[0-9]%', @String ) --Where is the first occurance of a number
            SELECT PATINDEX('%[0-9]%', REVERSE(@String)) --Flip the string and tell me from the other end where that number occurs
            SELECT LEN(@String) - PATINDEX('%[0-9 ].%[0-9]%', REVERSE(@String)) - PATINDEX('%[0-9]%', @String ) +2 --substract those from the length and add 2, tells me how long it is.

            --The above is basically where the number starts and it's length in the string.
            --Then use substring to pull it all out.
            SELECT SUBSTRING(@String, PATINDEX('%[0-9 ].%[0-9]%', @String ), LEN(@String) - PATINDEX('%[0-9]%', REVERSE(@String)) - PATINDEX('%[0-9 ].%[0-9]%', @String ) +2)

            --larger sample set
            IF OBJECT_ID('tempdb..#TestData') IS NOT NULL
            DROP TABLE #TestData

            CREATE TABLE #TestData (
            NumberData NVARCHAR(100)
            )

            INSERT INTO #TestData (
            [NumberData]
            )
            VALUES
            ('200g')
            ,('0.2KG')
            ,('0.200kg')
            ,('0.2')
            ,('0.2g(e)')
            ,('0.2000000k.g.')
            ,('grams 0.345')
            ,('This is k.g. 0.456 not g')
            ,('.456kg')

            SELECT *, SUBSTRING([NumberData], PATINDEX('%[0-9 ].%[0-9]%', [NumberData] ), LEN([NumberData]) - PATINDEX('%[0-9]%', REVERSE([NumberData])) - PATINDEX('%[0-9 ].%[0-9]%', [NumberData] ) +2)FROM #TestData





            share|improve this answer























            • Not entirely sure, but its having an issue running that. Say's theres incorrect syntax at the location ,('0.2KG')
              – A.Cassin
              Nov 15 at 15:40










            • @A.Cassin Sorry I don't see it. I just copied and pasted my example back out and ran it with no error.
              – Tim Mylott
              Nov 15 at 16:17












            • @A.Cassin oh wait, my bad, you're 2005 and this example is using a table variable which wasn't until 2008. I'll update so have a working example.
              – Tim Mylott
              Nov 15 at 16:21













            up vote
            0
            down vote










            up vote
            0
            down vote









            String parsing in T-SQL is always challenging. But with this situation, SUBSTRING might be easier.



            You mentioned this: letters are only ever at the start or end never inbetween the numbers



            So basically we just need to find where the number starts and ends in the string.



            Have a look at this:



            DECLARE @String NVARCHAR(100)

            SET @String = 'This is k.g. or g it''s .0456 not g'

            SELECT PATINDEX('%[0-9 ].%[0-9]%', @String ) --Where is the first occurance of a number
            SELECT PATINDEX('%[0-9]%', REVERSE(@String)) --Flip the string and tell me from the other end where that number occurs
            SELECT LEN(@String) - PATINDEX('%[0-9 ].%[0-9]%', REVERSE(@String)) - PATINDEX('%[0-9]%', @String ) +2 --substract those from the length and add 2, tells me how long it is.

            --The above is basically where the number starts and it's length in the string.
            --Then use substring to pull it all out.
            SELECT SUBSTRING(@String, PATINDEX('%[0-9 ].%[0-9]%', @String ), LEN(@String) - PATINDEX('%[0-9]%', REVERSE(@String)) - PATINDEX('%[0-9 ].%[0-9]%', @String ) +2)

            --larger sample set
            IF OBJECT_ID('tempdb..#TestData') IS NOT NULL
            DROP TABLE #TestData

            CREATE TABLE #TestData (
            NumberData NVARCHAR(100)
            )

            INSERT INTO #TestData (
            [NumberData]
            )
            VALUES
            ('200g')
            ,('0.2KG')
            ,('0.200kg')
            ,('0.2')
            ,('0.2g(e)')
            ,('0.2000000k.g.')
            ,('grams 0.345')
            ,('This is k.g. 0.456 not g')
            ,('.456kg')

            SELECT *, SUBSTRING([NumberData], PATINDEX('%[0-9 ].%[0-9]%', [NumberData] ), LEN([NumberData]) - PATINDEX('%[0-9]%', REVERSE([NumberData])) - PATINDEX('%[0-9 ].%[0-9]%', [NumberData] ) +2)FROM #TestData





            share|improve this answer














            String parsing in T-SQL is always challenging. But with this situation, SUBSTRING might be easier.



            You mentioned this: letters are only ever at the start or end never inbetween the numbers



            So basically we just need to find where the number starts and ends in the string.



            Have a look at this:



            DECLARE @String NVARCHAR(100)

            SET @String = 'This is k.g. or g it''s .0456 not g'

            SELECT PATINDEX('%[0-9 ].%[0-9]%', @String ) --Where is the first occurance of a number
            SELECT PATINDEX('%[0-9]%', REVERSE(@String)) --Flip the string and tell me from the other end where that number occurs
            SELECT LEN(@String) - PATINDEX('%[0-9 ].%[0-9]%', REVERSE(@String)) - PATINDEX('%[0-9]%', @String ) +2 --substract those from the length and add 2, tells me how long it is.

            --The above is basically where the number starts and it's length in the string.
            --Then use substring to pull it all out.
            SELECT SUBSTRING(@String, PATINDEX('%[0-9 ].%[0-9]%', @String ), LEN(@String) - PATINDEX('%[0-9]%', REVERSE(@String)) - PATINDEX('%[0-9 ].%[0-9]%', @String ) +2)

            --larger sample set
            IF OBJECT_ID('tempdb..#TestData') IS NOT NULL
            DROP TABLE #TestData

            CREATE TABLE #TestData (
            NumberData NVARCHAR(100)
            )

            INSERT INTO #TestData (
            [NumberData]
            )
            VALUES
            ('200g')
            ,('0.2KG')
            ,('0.200kg')
            ,('0.2')
            ,('0.2g(e)')
            ,('0.2000000k.g.')
            ,('grams 0.345')
            ,('This is k.g. 0.456 not g')
            ,('.456kg')

            SELECT *, SUBSTRING([NumberData], PATINDEX('%[0-9 ].%[0-9]%', [NumberData] ), LEN([NumberData]) - PATINDEX('%[0-9]%', REVERSE([NumberData])) - PATINDEX('%[0-9 ].%[0-9]%', [NumberData] ) +2)FROM #TestData






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 15 at 16:24

























            answered Nov 15 at 14:25









            Tim Mylott

            7988




            7988












            • Not entirely sure, but its having an issue running that. Say's theres incorrect syntax at the location ,('0.2KG')
              – A.Cassin
              Nov 15 at 15:40










            • @A.Cassin Sorry I don't see it. I just copied and pasted my example back out and ran it with no error.
              – Tim Mylott
              Nov 15 at 16:17












            • @A.Cassin oh wait, my bad, you're 2005 and this example is using a table variable which wasn't until 2008. I'll update so have a working example.
              – Tim Mylott
              Nov 15 at 16:21


















            • Not entirely sure, but its having an issue running that. Say's theres incorrect syntax at the location ,('0.2KG')
              – A.Cassin
              Nov 15 at 15:40










            • @A.Cassin Sorry I don't see it. I just copied and pasted my example back out and ran it with no error.
              – Tim Mylott
              Nov 15 at 16:17












            • @A.Cassin oh wait, my bad, you're 2005 and this example is using a table variable which wasn't until 2008. I'll update so have a working example.
              – Tim Mylott
              Nov 15 at 16:21
















            Not entirely sure, but its having an issue running that. Say's theres incorrect syntax at the location ,('0.2KG')
            – A.Cassin
            Nov 15 at 15:40




            Not entirely sure, but its having an issue running that. Say's theres incorrect syntax at the location ,('0.2KG')
            – A.Cassin
            Nov 15 at 15:40












            @A.Cassin Sorry I don't see it. I just copied and pasted my example back out and ran it with no error.
            – Tim Mylott
            Nov 15 at 16:17






            @A.Cassin Sorry I don't see it. I just copied and pasted my example back out and ran it with no error.
            – Tim Mylott
            Nov 15 at 16:17














            @A.Cassin oh wait, my bad, you're 2005 and this example is using a table variable which wasn't until 2008. I'll update so have a working example.
            – Tim Mylott
            Nov 15 at 16:21




            @A.Cassin oh wait, my bad, you're 2005 and this example is using a table variable which wasn't until 2008. I'll update so have a working example.
            – Tim Mylott
            Nov 15 at 16:21










            up vote
            0
            down vote













            You need to include . as part of a number. Rest is somewhat straight forward as long as there is a valid number present in the string after the first numeric character:



            DECLARE @t TABLE (test VARCHAR(256));
            INSERT INTO @t VALUES
            ('200g'),
            ('0.2kg'),
            ('0.200kg'),
            ('0.2g(e)'),
            ('0.2'),
            ('.2'),
            ('2KG'),
            ('2'),
            ('foo200bar'),
            ('foobar');

            SELECT *, CAST(substr2 AS DECIMAL(10, 4)) AS result
            FROM @t
            CROSS APPLY (SELECT PATINDEX('%[.0-9]%', test) AS pos1) AS ca1
            CROSS APPLY (SELECT CASE WHEN pos1 = 0 THEN NULL ELSE SUBSTRING(test, pos1, LEN(test) - pos1 + 1) END AS substr1) AS ca2
            CROSS APPLY (SELECT PATINDEX('%[^.0-9]%', substr1) AS pos2) AS ca3
            CROSS APPLY (SELECT CASE WHEN pos2 = 0 THEN substr1 ELSE SUBSTRING(substr1, 1, pos2 - 1) END AS substr2) AS ca4


            Demo on DB Fiddle



            Converted to function:



            CREATE FUNCTION dbo.fn_GetNumeric(@test VARCHAR(256)) RETURNS DECIMAL(10, 4) AS
            BEGIN
            DECLARE @pos1 AS INT = PATINDEX('%[.0-9]%', @test);
            IF @pos1 = 0 RETURN NULL;

            DECLARE @substr AS VARCHAR(256) = SUBSTRING(@test, @pos1, LEN(@test) - @pos1 + 1);

            DECLARE @pos2 AS INT = PATINDEX('%[^.0-9]%', @substr);
            IF @pos2 = 0 RETURN @substr;

            RETURN SUBSTRING(@substr, 1, @pos2 - 1);
            END


            Demo on DB Fiddle






            share|improve this answer























            • I'm sorry, i hadn't realised i didn't put that there can also be a condiiton where the data is written like 2KG so if that needs a valid number after the first, it will fail, correct?
              – A.Cassin
              Nov 15 at 14:55










            • 2KG becomes decimal 2.0000.
              – Salman A
              Nov 15 at 14:58












            • Hmm, Would you be able to rearrange this so it would work in a function at all that returns a value?
              – A.Cassin
              Nov 15 at 15:16










            • @A.Cassin see dbfiddle.uk/…
              – Salman A
              Nov 15 at 15:27










            • Ive seen that it only has a dropdown for 2012 as the oldest... Would you know that this would work in 2005? (i know its old)
              – A.Cassin
              Nov 15 at 15:36















            up vote
            0
            down vote













            You need to include . as part of a number. Rest is somewhat straight forward as long as there is a valid number present in the string after the first numeric character:



            DECLARE @t TABLE (test VARCHAR(256));
            INSERT INTO @t VALUES
            ('200g'),
            ('0.2kg'),
            ('0.200kg'),
            ('0.2g(e)'),
            ('0.2'),
            ('.2'),
            ('2KG'),
            ('2'),
            ('foo200bar'),
            ('foobar');

            SELECT *, CAST(substr2 AS DECIMAL(10, 4)) AS result
            FROM @t
            CROSS APPLY (SELECT PATINDEX('%[.0-9]%', test) AS pos1) AS ca1
            CROSS APPLY (SELECT CASE WHEN pos1 = 0 THEN NULL ELSE SUBSTRING(test, pos1, LEN(test) - pos1 + 1) END AS substr1) AS ca2
            CROSS APPLY (SELECT PATINDEX('%[^.0-9]%', substr1) AS pos2) AS ca3
            CROSS APPLY (SELECT CASE WHEN pos2 = 0 THEN substr1 ELSE SUBSTRING(substr1, 1, pos2 - 1) END AS substr2) AS ca4


            Demo on DB Fiddle



            Converted to function:



            CREATE FUNCTION dbo.fn_GetNumeric(@test VARCHAR(256)) RETURNS DECIMAL(10, 4) AS
            BEGIN
            DECLARE @pos1 AS INT = PATINDEX('%[.0-9]%', @test);
            IF @pos1 = 0 RETURN NULL;

            DECLARE @substr AS VARCHAR(256) = SUBSTRING(@test, @pos1, LEN(@test) - @pos1 + 1);

            DECLARE @pos2 AS INT = PATINDEX('%[^.0-9]%', @substr);
            IF @pos2 = 0 RETURN @substr;

            RETURN SUBSTRING(@substr, 1, @pos2 - 1);
            END


            Demo on DB Fiddle






            share|improve this answer























            • I'm sorry, i hadn't realised i didn't put that there can also be a condiiton where the data is written like 2KG so if that needs a valid number after the first, it will fail, correct?
              – A.Cassin
              Nov 15 at 14:55










            • 2KG becomes decimal 2.0000.
              – Salman A
              Nov 15 at 14:58












            • Hmm, Would you be able to rearrange this so it would work in a function at all that returns a value?
              – A.Cassin
              Nov 15 at 15:16










            • @A.Cassin see dbfiddle.uk/…
              – Salman A
              Nov 15 at 15:27










            • Ive seen that it only has a dropdown for 2012 as the oldest... Would you know that this would work in 2005? (i know its old)
              – A.Cassin
              Nov 15 at 15:36













            up vote
            0
            down vote










            up vote
            0
            down vote









            You need to include . as part of a number. Rest is somewhat straight forward as long as there is a valid number present in the string after the first numeric character:



            DECLARE @t TABLE (test VARCHAR(256));
            INSERT INTO @t VALUES
            ('200g'),
            ('0.2kg'),
            ('0.200kg'),
            ('0.2g(e)'),
            ('0.2'),
            ('.2'),
            ('2KG'),
            ('2'),
            ('foo200bar'),
            ('foobar');

            SELECT *, CAST(substr2 AS DECIMAL(10, 4)) AS result
            FROM @t
            CROSS APPLY (SELECT PATINDEX('%[.0-9]%', test) AS pos1) AS ca1
            CROSS APPLY (SELECT CASE WHEN pos1 = 0 THEN NULL ELSE SUBSTRING(test, pos1, LEN(test) - pos1 + 1) END AS substr1) AS ca2
            CROSS APPLY (SELECT PATINDEX('%[^.0-9]%', substr1) AS pos2) AS ca3
            CROSS APPLY (SELECT CASE WHEN pos2 = 0 THEN substr1 ELSE SUBSTRING(substr1, 1, pos2 - 1) END AS substr2) AS ca4


            Demo on DB Fiddle



            Converted to function:



            CREATE FUNCTION dbo.fn_GetNumeric(@test VARCHAR(256)) RETURNS DECIMAL(10, 4) AS
            BEGIN
            DECLARE @pos1 AS INT = PATINDEX('%[.0-9]%', @test);
            IF @pos1 = 0 RETURN NULL;

            DECLARE @substr AS VARCHAR(256) = SUBSTRING(@test, @pos1, LEN(@test) - @pos1 + 1);

            DECLARE @pos2 AS INT = PATINDEX('%[^.0-9]%', @substr);
            IF @pos2 = 0 RETURN @substr;

            RETURN SUBSTRING(@substr, 1, @pos2 - 1);
            END


            Demo on DB Fiddle






            share|improve this answer














            You need to include . as part of a number. Rest is somewhat straight forward as long as there is a valid number present in the string after the first numeric character:



            DECLARE @t TABLE (test VARCHAR(256));
            INSERT INTO @t VALUES
            ('200g'),
            ('0.2kg'),
            ('0.200kg'),
            ('0.2g(e)'),
            ('0.2'),
            ('.2'),
            ('2KG'),
            ('2'),
            ('foo200bar'),
            ('foobar');

            SELECT *, CAST(substr2 AS DECIMAL(10, 4)) AS result
            FROM @t
            CROSS APPLY (SELECT PATINDEX('%[.0-9]%', test) AS pos1) AS ca1
            CROSS APPLY (SELECT CASE WHEN pos1 = 0 THEN NULL ELSE SUBSTRING(test, pos1, LEN(test) - pos1 + 1) END AS substr1) AS ca2
            CROSS APPLY (SELECT PATINDEX('%[^.0-9]%', substr1) AS pos2) AS ca3
            CROSS APPLY (SELECT CASE WHEN pos2 = 0 THEN substr1 ELSE SUBSTRING(substr1, 1, pos2 - 1) END AS substr2) AS ca4


            Demo on DB Fiddle



            Converted to function:



            CREATE FUNCTION dbo.fn_GetNumeric(@test VARCHAR(256)) RETURNS DECIMAL(10, 4) AS
            BEGIN
            DECLARE @pos1 AS INT = PATINDEX('%[.0-9]%', @test);
            IF @pos1 = 0 RETURN NULL;

            DECLARE @substr AS VARCHAR(256) = SUBSTRING(@test, @pos1, LEN(@test) - @pos1 + 1);

            DECLARE @pos2 AS INT = PATINDEX('%[^.0-9]%', @substr);
            IF @pos2 = 0 RETURN @substr;

            RETURN SUBSTRING(@substr, 1, @pos2 - 1);
            END


            Demo on DB Fiddle







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 15 at 18:00

























            answered Nov 15 at 14:47









            Salman A

            174k66334421




            174k66334421












            • I'm sorry, i hadn't realised i didn't put that there can also be a condiiton where the data is written like 2KG so if that needs a valid number after the first, it will fail, correct?
              – A.Cassin
              Nov 15 at 14:55










            • 2KG becomes decimal 2.0000.
              – Salman A
              Nov 15 at 14:58












            • Hmm, Would you be able to rearrange this so it would work in a function at all that returns a value?
              – A.Cassin
              Nov 15 at 15:16










            • @A.Cassin see dbfiddle.uk/…
              – Salman A
              Nov 15 at 15:27










            • Ive seen that it only has a dropdown for 2012 as the oldest... Would you know that this would work in 2005? (i know its old)
              – A.Cassin
              Nov 15 at 15:36


















            • I'm sorry, i hadn't realised i didn't put that there can also be a condiiton where the data is written like 2KG so if that needs a valid number after the first, it will fail, correct?
              – A.Cassin
              Nov 15 at 14:55










            • 2KG becomes decimal 2.0000.
              – Salman A
              Nov 15 at 14:58












            • Hmm, Would you be able to rearrange this so it would work in a function at all that returns a value?
              – A.Cassin
              Nov 15 at 15:16










            • @A.Cassin see dbfiddle.uk/…
              – Salman A
              Nov 15 at 15:27










            • Ive seen that it only has a dropdown for 2012 as the oldest... Would you know that this would work in 2005? (i know its old)
              – A.Cassin
              Nov 15 at 15:36
















            I'm sorry, i hadn't realised i didn't put that there can also be a condiiton where the data is written like 2KG so if that needs a valid number after the first, it will fail, correct?
            – A.Cassin
            Nov 15 at 14:55




            I'm sorry, i hadn't realised i didn't put that there can also be a condiiton where the data is written like 2KG so if that needs a valid number after the first, it will fail, correct?
            – A.Cassin
            Nov 15 at 14:55












            2KG becomes decimal 2.0000.
            – Salman A
            Nov 15 at 14:58






            2KG becomes decimal 2.0000.
            – Salman A
            Nov 15 at 14:58














            Hmm, Would you be able to rearrange this so it would work in a function at all that returns a value?
            – A.Cassin
            Nov 15 at 15:16




            Hmm, Would you be able to rearrange this so it would work in a function at all that returns a value?
            – A.Cassin
            Nov 15 at 15:16












            @A.Cassin see dbfiddle.uk/…
            – Salman A
            Nov 15 at 15:27




            @A.Cassin see dbfiddle.uk/…
            – Salman A
            Nov 15 at 15:27












            Ive seen that it only has a dropdown for 2012 as the oldest... Would you know that this would work in 2005? (i know its old)
            – A.Cassin
            Nov 15 at 15:36




            Ive seen that it only has a dropdown for 2012 as the oldest... Would you know that this would work in 2005? (i know its old)
            – A.Cassin
            Nov 15 at 15:36


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53320847%2ftrying-to-get-all-numerical-values-and-periods-form-string%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            404 Error Contact Form 7 ajax form submitting

            How to know if a Active Directory user can login interactively

            TypeError: fit_transform() missing 1 required positional argument: 'X'