Séparez les lettres des chiffres dans une chaîne alphanumérique

9

J'ai une chaîne alphanumérique en entrée et je veux en obtenir deux résultats:

  • une chaîne où tous les chiffres sont supprimés

    et

  • un entier qui est la somme de tous les chiffres de la chaîne d'entrée.

Par exemple, pour cette entrée:

GR35hc7vdH35

Je veux la sortie suivante:

| Col1.         |        Col2    |
----------------------------------
| GRhcvdH       |        23      |

Comment est-ce possible?

user93438
la source

Réponses:

8

SQL Server ne prend pas en charge le remplacement des modèles de plusieurs caractères, donc le faire via REPLACEnécessiterait potentiellement 10 opérations.

Dans cet esprit, une façon de procéder serait un CTE récursif pour traiter les chiffres de 0 à 9 de manière séquentielle.

Il effectue le remplacement et vérifie ensuite la longueur des chaînes avant et après pour savoir combien de caractères de ce nombre il y avait et ce qui doit être ajouté au total.

DECLARE @Input VARCHAR(8000) = 'GR35hc7vdH35';

WITH R(Level,Input,Accumulator,StringLength)
     AS (SELECT 0,
                Input,
                0,
                DATALENGTH(Input)
         FROM   (SELECT REPLACE(@Input, '0', '')) D(Input)
         UNION ALL
         SELECT NewLevel,
                NewInput,
                Accumulator + NewLevel * ( StringLength - NewStringLength ),
                NewStringLength
         FROM   R
                CROSS APPLY (SELECT Level + 1) C(NewLevel)
                CROSS APPLY (SELECT REPLACE(Input, NewLevel, '')) C2(NewInput)
                CROSS APPLY (SELECT DATALENGTH(NewInput)) C3(NewStringLength)
         WHERE  NewLevel <= 9)
SELECT Input       AS Col1,
       Accumulator AS Col2
FROM   R
WHERE  Level = 9;

Ou vous pouvez utiliser CLR et des expressions régulières (version compatible avec SQL Server 2012).

using System;
using System.Data.SqlTypes;
using System.Collections;
using System.Text.RegularExpressions;

public partial class UserDefinedFunctions
{
    private static readonly Regex digitRegex = new Regex(@"[\d]", RegexOptions.Compiled);

    [Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName = "FillRow",
                                            TableDefinition = @"Stripped NVARCHAR(MAX),
                                                                Total INT")]

    public static IEnumerable ReplaceAndTotalise(SqlString input)
    {
        if (!input.IsNull)
        {
            int total = 0;
            string stripped = digitRegex.Replace((string)input, match =>
            {
                total += int.Parse(match.Value);
                return string.Empty;
            });

            yield return new Tuple<string, int>(stripped, total);
        }
    }

    public static void FillRow(object resultObject, out SqlString stripped, out SqlInt32 total)
    {
        var result = (Tuple<string, int>)resultObject;
        stripped = result.Item1;
        total = result.Item2;

    }
}

Exemple d'utilisation

SELECT Stripped,
       Total
FROM   [dbo].[ReplaceAndTotalise]('GR35hc7vdH35') 
Martin Smith
la source
5

Essayez ce qui suit:

CREATE FUNCTION dbo.AlphaNumericSplitter 
(
    @string varchar(8000)
)
RETURNS TABLE
AS
RETURN  (
    WITH    Alphanumeric (col1)
    AS      (
            -- Put out string into a cte table
            SELECT @string
            ),
            Nmbrs (n)
    AS      (
            -- Numbers so we can split the string
            SELECT  TOP(LEN(@string))
                    ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
            FROM    sys.all_objects AS o1
            CROSS
            JOIN    sys.all_objects AS o2
            ),
            y
    AS      (
            SELECT  N.n
                    a.col1,
                    N.x,
                    -- Get the numbers only
                    Numbers = TRY_CONVERT(int, N.x)
            FROM    Alphanumeric AS a
            CROSS 
            APPLY   (SELECT [x] = SUBSTRING(a.col1, n, 1), Nmbrs.n FROM Nmbrs) AS N
            )
    SELECT  z.Col1,
            Col2 = SUM(y.Numbers)
    FROM    y
    --  Get the letters only
    CROSS
    APPLY   (SELECT (SELECT x + '' FROM y WHERE Numbers IS NULL ORDER BY y.n FOR XML PATH(''))) AS z (Col1)
    GROUP   BY
            z.Col1);
GO

SELECT * FROM AlphaNumericSplitter('GR35hc7vdH35');

Résultats:

entrez la description de l'image ici

Shaneis
la source
2

En quelque sorte

... r.s ...
cross apply (
  select s = sum(cast(substring(mycol,i,1) as int)) 
  from (select top(len(mycol)) i = row_number() over(order by (select null))
    from sys.all_objects,sys.all_objects) tally
  where substring(mycol,i,1) like '[0-9]'
) r
Serg
la source
0

Utilisez la fonction suivante pour extraire les alphabets de la chaîne

CREATE FUNCTION dbo.udf_GetAlphabets
(@strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256)
AS
BEGIN
DECLARE @intAlpha INT
SET @intAlpha = PATINDEX('%[a-zA-Z]%', @strAlphaNumeric)
BEGIN
WHILE @intAlpha > 0
BEGIN
SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
SET @intAlpha = PATINDEX('%[a-zA-Z]%', @strAlphaNumeric )
END
END
RETURN ISNULL(@strAlphaNumeric,0)
END
GO

Utilisez la fonction suivante pour extraire les nombres de la chaîne

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
GO

Utilisez la requête suivante pour extraire les deux en une seule commande:

SELECT dbo.udf_GetNumeric(column_name) Number, dbo.udf_GetAlphabets(column_name) Chars
from table_name
Légion du chaos
la source