t-sql - применить функцию к столбцу без sqlFunction - PullRequest
0 голосов
/ 12 февраля 2019

Я должен преобразовать числовой код в буквенный код, например:

1234 -> ABCD

, где 0 = 0, 1 = A, 2 = b и т. Д.

Это моя функция и способ ее использования:

Create function dbo.DecodeNumToChar
(
    @change varchar(10),
    @foo varchar(10)
) returns varchar(10)
as
begin
    DECLARE @II int = 1,
            @result varchar(10)
    ;WITH x AS 
    (
        SELECT @II as ii, STUFF(@foo,@II,1,SUBSTRING(@change,CAST(SUBSTRING(@foo,@II,1) AS INT)+1,1)) AS AA
        UNION ALL
        --SELECT @II+1
        SELECT  ii+1, STUFF(AA,ii+1,1,SUBSTRING(@change,CAST(SUBSTRING(@foo,ii+1,1) AS INT)+1,1)) AS AA
        FROM x 
        where ii+1 <= LEN(@foo)
    )

    select top 1 @result = AA from x order by ii desc
    return @result
end
--------------------------------------------
select brand_code, dbo.DecodeNumToChar('0ABCDEFGHI', brand_code) 
from (VALUES('1234'),('5834'),('9905'),('0250')) as t(brand_code)

Эта функция работает хорошо, но в производственной БД у нас нет разрешения на создание функций.

I 'мы пытались преобразовать эту функцию в CTE, как это

declare @change varchar(9) = 'ABCDEFGHI'
DECLARE @II int = 0

;WITH x AS 
(
  SELECT TOP (10) n = ROW_NUMBER() OVER (ORDER BY Number)
  FROM master.dbo.spt_values ORDER BY Number
),
innerCTE as
(
    SELECT x.n, SUBSTRING(t.brand_code, x.n, 1) chnum, 
    case SUBSTRING(t.brand_code, x.n, 1)
        when '0' then '0'
        else char(65-1+SUBSTRING(t.brand_code, x.n, 1))
    end chalfa, t.brand_code
    FROM x INNER JOIN (VALUES('1234'),('5834'),('9905'),('0250')) as t(brand_code)
    ON x.n <= LEN(t.brand_code)
),
CTE as
(
    select n, chnum, chalfa, brand_code, stuff(brand_code, n, 1, chalfa) as code
    from innerCTE
    union all 
    select n+1, chnum, chalfa, brand_code, STUFF(code, n+1, 1, chalfa) as code
    from cte
    where n+1 <= LEN(cte.brand_code)
)
--select * from innerCTE
select * from CTE;

, или использовать CROSS APPLY, как в этом примере: Example_1

, или использовать CROSS APPLY с PIVOT, как в этом примере: Example_2

но мой опыт работы с SQL низок, и я не смог получить правильный результат.

Я хотел бы получить это:

brand_code  decoded_code
1234        ABCD
5834        EHCD
9905        II0E
0250        0BE0

спасибо

Ответы [ 4 ]

0 голосов
/ 12 февраля 2019

Это код предложения от @Martin Smith использовать 10 вложенных замен.

DECLARE @change char(10) = '0ABCDEFGHI';
--------------------------------------------
select brand_code,
    REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( 
    REPLACE( REPLACE( REPLACE( REPLACE( REPLACE( brand_code
    , '0', SUBSTRING( @change, 1, 1)) , '1', SUBSTRING( @change, 2, 1)) 
    , '2', SUBSTRING( @change, 3, 1)) , '3', SUBSTRING( @change, 4, 1)) 
    , '4', SUBSTRING( @change, 5, 1)) , '5', SUBSTRING( @change, 6, 1)) 
    , '6', SUBSTRING( @change, 7, 1)) , '7', SUBSTRING( @change, 8, 1)) 
    , '8', SUBSTRING( @change, 9, 1)) , '9', SUBSTRING( @change, 10, 1)) 
from (VALUES('1234'),('5834'),('9905'),('0250')) as t(brand_code);
0 голосов
/ 12 февраля 2019

Я нашел решение с использованием рекурсивного CTE.

declare @change varchar(10) = '0ABCDEFGHI'
DECLARE @II int = 1;

with BRANDS as
(
    select * from (VALUES('1234'),('5834'),('9905'),('0250')) as t(brand_code)
),
CTE as
(
    select  @II as ii, BRAND_CODE, 
            STUFF(brand_code,@II,1,SUBSTRING(@change,CAST(SUBSTRING(brand_code,@II,1) AS INT)+1,1)) AS AA
    from BRANDS
    union all
    select  c.ii+1, b.BRAND_CODE, 
            STUFF(AA,c.ii+1,1,SUBSTRING(@change,CAST(SUBSTRING(AA,c.ii+1,1) AS INT)+1,1)) AS AA
    from BRANDS b
    inner join CTE c on b.BRAND_CODE = c.BRAND_CODE
    where c.ii < LEN(b.BRAND_CODE)
)

select BRAND_CODE, AA as NewCode from CTE where ii = len(brand_code) order by BRAND_CODE, ii
0 голосов
/ 12 февраля 2019

При использовании SQL 2017 +

DECLARE @integerValues TABLE ([I] INT);

INSERT INTO @integerValues ([I])
VALUES
    (1234),
    (6485834),
    (99084705),
    (1124601);

SELECT
            T.[I],
            STRING_AGG(
                CASE SUBSTRING(T.[S], V.[number] + 1, 1)
                    WHEN '9' THEN 'I'
                    WHEN '8' THEN 'H'
                    WHEN '7' THEN 'G'
                    WHEN '6' THEN 'F'
                    WHEN '5' THEN 'E'
                    WHEN '4' THEN 'D'
                    WHEN '3' THEN 'C'
                    WHEN '2' THEN 'B'
                    WHEN '1' THEN 'A'
                    ELSE '0'
                END,
                '') WITHIN GROUP (ORDER BY T.[I]) [S]
    FROM
            (SELECT [I], CAST([I] AS VARCHAR(10)) [S] FROM @integerValues) T
        JOIN
            [master]..[spt_values] V ON V.[number] < LEN(T.[S])
    WHERE
        V.[type] = 'P';

или, если 2016 или более ранняя версия

DECLARE @integerValues TABLE ([I] INT);

INSERT INTO @integerValues ([I])
VALUES
    (1234),
    (6485834),
    (99084705),
    (1124601);

SELECT
        [I],
        REPLACE(
            REPLACE(
                REPLACE(
                    REPLACE(
                        REPLACE(
                            REPLACE(
                                REPLACE(
                                    REPLACE(
                                        REPLACE(
                                            CAST([I] AS VARCHAR(10)),
                                            '1',
                                            'A'),
                                        '2',
                                        'B'),
                                    '3',
                                    'C'),
                                '4',
                                'D'),
                            '5',
                            'E'),
                        '6',
                        'F'),
                    '7',
                    'G'),
                '8',
                'H'),
            '9',
            'I') [S]
    FROM
        @integerValues;
0 голосов
/ 12 февраля 2019

Следующее решение использует подзапрос FOR XML и некоторые операции mod (%) для целочисленного значения, чтобы разделить каждую цифру, а затем таблицу сопоставления, чтобы связать каждую цифру с символом.FOR XML возвращает цифры в обратном порядке.

DECLARE @IntegerValues TABLE (Integer INT)

INSERT INTO @IntegerValues (Integer)
VALUES
    (1234),
    (6485834),
    (99084705),
    (1124601)

SELECT
    T.Integer,
    Conversion = (
            SELECT
                '' + M.Character -- Must have no declared alias (for xml)
            FROM
                (VALUES
                    (1, T.Integer                       % 10),
                    (2, T.Integer /  10                 % 10),
                    (3, T.Integer /  100                % 10),
                    (4, T.Integer /  1000               % 10),
                    (5, T.Integer /  10000              % 10),
                    (6, T.Integer /  100000             % 10),
                    (7, T.Integer /  1000000            % 10),
                    (8, T.Integer /  10000000           % 10),
                    (9, T.Integer /  100000000          % 10),
                    (10, T.Integer / 1000000000         % 10),
                    (11, T.Integer / 10000000000        % 10)
                ) AS X(OrdinalPosition, SplitDigit)
                INNER JOIN (VALUES
                    (0, '0'),
                    (1, 'A'),
                    (2, 'B'),
                    (3, 'C'),
                    (4, 'D'),
                    (5, 'E'),
                    (6, 'F'),
                    (7, 'G'),
                    (8, 'H'),
                    (9, 'I')
                ) AS M(Digit, Character) ON X.SplitDigit = M.Digit
            WHERE
                X.OrdinalPosition <= FLOOR(LOG10(T.Integer)) + 1 -- This expression returns the number of digits
            ORDER BY
                X.OrdinalPosition DESC
            FOR XML
                PATH('')
        )
FROM
    @IntegerValues AS T

Результат:

Integer     Conversion
1234        ABCD
6485834     FDHEHCD
99084705    II0HDG0E
1124601     AABDF0A

Возможно, есть более чистый способ записи сопоставлений и операций мода, но это должно датьидея.

...