Отделяйте буквы от цифр в буквенно-цифровой строке

9

У меня есть буквенно-цифровая строка в качестве ввода, и я хочу получить из нее два результата:

  • строка, в которой удалены все цифры

    а также

  • целое число, которое является суммой всех цифр во входной строке.

Например, для этого ввода:

GR35hc7vdH35

Я хочу следующий вывод:

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

Как это сделать?

user93438
источник

Ответы:

8

SQL Server не поддерживает замену шаблонов из нескольких символов, поэтому для его выполнения REPLACEпотребовалось бы потенциально 10 операций.

Имея это в виду, одним из способов было бы рекурсивное CTE для последовательной обработки цифр 0-9.

Он выполняет замену, а затем проверяет длину строк «до» и «после», чтобы узнать, сколько символов этого числа было и что нужно добавить к общему количеству.

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;

Или вы можете использовать CLR и регулярные выражения (версия, совместимая с 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;

    }
}

Пример использования

SELECT Stripped,
       Total
FROM   [dbo].[ReplaceAndTotalise]('GR35hc7vdH35') 
Мартин Смит
источник
5

Попробуйте следующее:

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');

Результаты:

введите описание изображения здесь

Shaneis
источник
2

Вроде

... 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
источник
0

Используйте следующую функцию для извлечения алфавитов из строки

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

Используйте следующую функцию, чтобы извлечь числа из строки

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

Используйте следующий запрос для извлечения обоих в одной команде:

SELECT dbo.udf_GetNumeric(column_name) Number, dbo.udf_GetAlphabets(column_name) Chars
from table_name
Хаос Легион
источник