t-sql-将函数应用于没有sqlFunction

时间:2019-02-12 11:03:30

标签: sql-server tsql common-table-expression cross-apply

我必须将数字代码转换为这样的字母代码:

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)

此功能运行良好,但是在生产数据库中,我们无权创建功能。

我已经尝试过将此功能转换为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

或将交叉应用与PIVOT一起使用,例如以下示例:Example_2

但是我在SQL方面的经验很差,无法获得正确的结果。

我想要这个:

brand_code  decoded_code
1234        ABCD
5834        EHCD
9905        II0E
0250        0BE0

谢谢

4 个答案:

答案 0 :(得分:1)

如果使用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;

答案 1 :(得分:0)

以下解决方案对整数值使用<section class="gallery-links"> <img class="gallery-img" src="https://www.w3schools.com/howto/img_forest.jpg" alt="img1"> <img class="gallery-img" src="https://www.w3schools.com/howto/img_forest.jpg" alt="img2"> <img class="gallery-img" src="https://www.w3schools.com/howto/img_forest.jpg" alt="img3"> <img class="gallery-img" src="https://www.w3schools.com/howto/img_forest.jpg" alt="img4"> <img class="gallery-img" src="https://www.w3schools.com/howto/img_forest.jpg" alt="img1"> <img class="gallery-img" src="https://www.w3schools.com/howto/img_forest.jpg" alt="img2"> <img class="gallery-img" src="https://www.w3schools.com/howto/img_forest.jpg" alt="img3"> </section>子查询和某些mod(FOR XML)操作来分割每个数字,然后使用映射表将每个数字与一个字符相关联。 %按顺序返回数字。

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

也许可以使用一种更简洁的方式来编写映射和mod操作,但这应该可以提供一个思路。

答案 2 :(得分:0)

我找到了使用递归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

答案 3 :(得分:0)

这是@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);