如何在SQL中构建smiliar-VLOOKUP函数

如何在SQL中构建smiliar-VLOOKUP函数,sql,sql-server,tsql,Sql,Sql Server,Tsql,我在excel中有一个小的校验位算法,它基本上是一个VLOOKUP函数。现在,我想在sql中生成具有相同结果的函数 为了检查数字,我为此设置了一个静态表 我从0(橙色)开始,然后我的vlookup函数是: =SVERWEIS(C16;$A$4:$K$13;B17+2;FALSCH) 翻译成英语 =VLOOKUP(C16;$A$4:$K$13;B17+2;FALSE) 如何检查“校验位” 首先,我查看0(C16)列(橙色单元格) 在第9行(b17)的传输列中,这两个数字的组合=5(我的新

我在excel中有一个小的校验位算法,它基本上是一个VLOOKUP函数。现在,我想在sql中生成具有相同结果的函数

为了检查数字,我为此设置了一个静态表

我从0(橙色)开始,然后我的vlookup函数是:

=SVERWEIS(C16;$A$4:$K$13;B17+2;FALSCH)
翻译成英语

=VLOOKUP(C16;$A$4:$K$13;B17+2;FALSE)

如何检查“校验位”

首先,我查看0(C16)列(橙色单元格) 在第9行(b17)的传输列中,这两个数字的组合=5(我的新传输) 下一个 现在我在街上放血 传输列第5行和(B18)=6->这是列 组合现在是第5行(转移)和第6列->我的新转移是9 下一个 组合现在是第9行(转移)和第9列->我的新转移是3 所以有一个。。。 在第一个示例中,最后一个数字应该是2(C42)。。。此数字计算为负10->10-2=8
到目前为止我所做的:

我在sql中创建了一个新表,其中包含校验位Tbl

CREATE TABLE CheckTbl(
   transfer    INTEGER  NOT NULL PRIMARY KEY 
  ,0           INTEGER  NOT NULL
  ,1           INTEGER  NOT NULL
  ,2           INTEGER  NOT NULL
  ,3           INTEGER  NOT NULL
  ,4           INTEGER  NOT NULL
  ,5           INTEGER  NOT NULL
  ,6           INTEGER  NOT NULL
  ,7           INTEGER  NOT NULL
  ,8           INTEGER  NOT NULL
  ,9           INTEGER  NOT NULL
  ,check_digit INTEGER  NOT NULL
);
INSERT INTO CheckTbl(transfer,0,1,2,3,4,5,6,7,8,9,check_digit) VALUES (0,0,9,4,6,8,2,7,1,3,5,0);
INSERT INTO CheckTbl(transfer,0,1,2,3,4,5,6,7,8,9,check_digit) VALUES (1,9,4,6,8,2,7,1,3,5,0,9);
INSERT INTO CheckTbl(transfer,0,1,2,3,4,5,6,7,8,9,check_digit) VALUES (2,4,6,8,2,7,1,3,5,0,9,8);
INSERT INTO CheckTbl(transfer,0,1,2,3,4,5,6,7,8,9,check_digit) VALUES (3,6,8,2,7,1,3,5,0,9,4,7);
INSERT INTO CheckTbl(transfer,0,1,2,3,4,5,6,7,8,9,check_digit) VALUES (4,8,2,7,1,3,5,0,9,4,6,6);
INSERT INTO CheckTbl(transfer,0,1,2,3,4,5,6,7,8,9,check_digit) VALUES (5,2,7,1,3,5,0,9,4,6,8,5);
INSERT INTO CheckTbl(transfer,0,1,2,3,4,5,6,7,8,9,check_digit) VALUES (6,7,1,3,5,0,9,4,6,8,2,4);
INSERT INTO CheckTbl(transfer,0,1,2,3,4,5,6,7,8,9,check_digit) VALUES (7,1,3,5,0,9,4,6,8,2,7,3);
INSERT INTO CheckTbl(transfer,0,1,2,3,4,5,6,7,8,9,check_digit) VALUES (8,3,5,0,9,4,6,8,2,7,1,2);
INSERT INTO CheckTbl(transfer,0,1,2,3,4,5,6,7,8,9,check_digit) VALUES (9,5,0,9,4,6,8,2,7,1,3,1);
我的sql:

DECLARE @refNr nvarchar(30) = '9699100000030000201830'
DECLARE @str VARCHAR(50), @Inc INT, @len INT, @char VARCHAR(50)


SET @str = @refNr
SET @Inc = 1
SET @len = LEN(@str)

WHILE @Inc<= @len
BEGIN
  SET @char = COALESCE(@char+',' ,'') + SUBSTRING(@str, @Inc, 1)  
  SET @Inc=@Inc+1
END


SELECT [value] FROM string_split(@char, ',') WHERE RTRIM(value) <> ''; 

SELECT [transfer]
      ,[0],[1],[2],[3],[4],[5],[6],[7],[8],[9]
      ,[check_digit]
  FROM [CCHelper].[dbo].[CheckTbl]


  SELECT 
    [value] 
  FROM 
    string_split(@char, ',') as SS
    LEFT JOIN CheckTbl CT on (SS.[value] = CT. .....)
DECLARE@refNr nvarchar(30)='96991000000000201830'
声明@str VARCHAR(50)、@Inc INT、@len INT、@char VARCHAR(50)
SET@str=@refNr
设置@Inc=1
设置@len=len(@str)

虽然@Inc我不认为我真的100%理解它是如何工作的,但我通过Excel VLOOKUP工作,我可以为您的第一个示例得到答案,但它不是特别令人愉快

SET NOCOUNT ON;
DECLARE @check_digits TABLE (
    [transfer] INT,
    d0 INT,
    d1 INT,
    d2 INT,
    d3 INT,
    d4 INT,
    d5 INT,
    d6 INT,
    d7 INT,
    d8 INT,
    d9 INT,
    check_digit INT);
INSERT INTO @check_digits SELECT 0,0,9,4,6,8,2,7,1,3,5,0;
INSERT INTO @check_digits SELECT 1,9,4,6,8,2,7,1,3,5,0,9;
INSERT INTO @check_digits SELECT 2,4,6,8,2,7,1,3,5,0,9,8;
INSERT INTO @check_digits SELECT 3,6,8,2,7,1,3,5,0,9,4,7;
INSERT INTO @check_digits SELECT 4,8,2,7,1,3,5,0,9,4,6,6;
INSERT INTO @check_digits SELECT 5,2,7,1,3,5,0,9,4,6,8,5;
INSERT INTO @check_digits SELECT 6,7,1,3,5,0,9,4,6,8,2,4;
INSERT INTO @check_digits SELECT 7,1,3,5,0,9,4,6,8,2,7,3;
INSERT INTO @check_digits SELECT 8,3,5,0,9,4,6,8,2,7,1,2;
INSERT INTO @check_digits SELECT 9,5,0,9,4,6,8,2,7,1,3,1;

DECLARE @offset TABLE (
    id INT,
    offset INT);
INSERT INTO @offset
SELECT 1, 9
UNION ALL
SELECT 2, 6
UNION ALL
SELECT 3, 9
UNION ALL
SELECT 4, 9
UNION ALL
SELECT 5, 1
UNION ALL
SELECT 6, 0
UNION ALL
SELECT 7, 0
UNION ALL
SELECT 8, 0
UNION ALL
SELECT 9, 0
UNION ALL
SELECT 10, 0
UNION ALL
SELECT 11, 0
UNION ALL
SELECT 12, 3
UNION ALL
SELECT 13, 0
UNION ALL
SELECT 14, 0
UNION ALL
SELECT 15, 0
UNION ALL
SELECT 16, 0
UNION ALL
SELECT 17, 2
UNION ALL
SELECT 18, 0
UNION ALL
SELECT 19, 1
UNION ALL
SELECT 20, 8
UNION ALL
SELECT 21, 3
UNION ALL
SELECT 22, 0
UNION ALL
SELECT 23, 0
UNION ALL
SELECT 24, 0
UNION ALL
SELECT 25, 8
UNION ALL
SELECT 26, 7;

DECLARE @transfer INT = 0;
DECLARE @offset_value INT;
DECLARE @iterations INT = 1;
WHILE @iterations <= 26
BEGIN
    SELECT @offset_value = offset + 2 FROM @offset WHERE id = @iterations;
    SELECT @transfer = 
        CASE
            WHEN @offset_value = 2 THEN d0
            WHEN @offset_value = 3 THEN d1
            WHEN @offset_value = 4 THEN d2
            WHEN @offset_value = 5 THEN d3
            WHEN @offset_value = 6 THEN d4
            WHEN @offset_value = 7 THEN d5
            WHEN @offset_value = 8 THEN d6
            WHEN @offset_value = 9 THEN d7
            WHEN @offset_value = 10 THEN d8
            WHEN @offset_value = 11 THEN d9
        END
    FROM 
        @check_digits
    WHERE
        [transfer] = @transfer;
    SELECT @iterations = @iterations + 1;
END;
PRINT 'Check Digit is ' + CONVERT(CHAR(1), 10 - @transfer);
SET NOCOUNT OFF;
设置不计数;
声明@check_数字表(
[transfer]INT,
d0 INT,
d1 INT,
d2 INT,
d3 INT,
d4 INT,
d5 INT,
d6 INT,
d7 INT,
d8 INT,
d9 INT,
检查数字(整数);
在@check_数字中插入0,0,9,4,6,8,2,7,1,3,5,0;
在@check_数字中插入1,9,4,6,8,2,7,1,3,5,0,9;
在@check_数字中插入选择2,4,6,8,2,7,1,3,5,0,9,8;
在@check_数字中插入选择3,6,8,2,7,1,3,5,0,9,4,7;
在@check_数字中插入选择4,8,2,7,1,3,5,0,9,4,6,6;
在@check_数字中插入选择5,2,7,1,3,5,0,9,4,6,8,5;
在@check_数字中插入选择6,7,1,3,5,0,9,4,6,8,2,4;
在@check_数字中插入7,1,3,5,0,9,4,6,8,2,7,3;
在@check_数字中插入8,3,5,0,9,4,6,8,2,7,1,2;
在@check_数字中插入选择9,5,0,9,4,6,8,2,7,1,3,1;
声明@offset表(
id INT,
偏移量(整数);
插入到@offset中
选择1、9
联合所有
选择2、6
联合所有
选择3、9
联合所有
选择4、9
联合所有
选择5,1
联合所有
选择6,0
联合所有
选择7,0
联合所有
选择8,0
联合所有
选择9,0
联合所有
选择10,0
联合所有
选择11,0
联合所有
选择12,3
联合所有
选择13,0
联合所有
选择14,0
联合所有
选择15,0
联合所有
选择16,0
联合所有
选择17,2
联合所有
选择18,0
联合所有
选择19,1
联合所有
选择20、8
联合所有
选择21,3
联合所有
选择22,0
联合所有
选择23,0
联合所有
选择24,0
联合所有
选择25,8
联合所有
选择26,7;
声明@transfer INT=0;
声明@offset_值INT;
声明@iterations INT=1;

当@iterations使用您上面显示的带有校验位的表格时,您能提供一个“vlookup”的例子吗?数据的图片通常对其他人没有帮助,因为我们使用它的唯一方法是转录它;这不是很多人想花/浪费时间做的事情。如果您将数据发布为
文本
(或者更好的DDL和DLM语句),您将更有可能收到有用的答案。抱歉,图片太多了。我编辑了我的问题,看到while循环创建了一个逗号分隔的列表并传递给字符串拆分器,我有些畏缩。这是需要理货台的地方。您不需要循环或拆分器来完成此操作。感谢您干净地发布数据。但我根本无法理解你们在这里要做什么。第一个数字总是0。我想我可以为它做一个小函数,比如checkdigit('longNumber'),它会输出校验和。与此相关的业务是。我想检查700k长号码是否正确存储。我的第一个想法是在excel中创建这个结构,看看它是如何工作的。它对VLOOKUP的作用比我想象的好也许我可以在SQL中构建一个smiliar函数。但不幸的是,我认为这是一个坏主意,我必须做这个递归运算。这是一个非常简单的校验和,如果你得到一个0,那么10-0=10,这是两位数,在我眼里这不是一个校验位数…谢谢你的时间。你解决这个问题的方法对我帮助很大!我用一个解决方案更新了我的问题。你不能得到10的校验和。如果您查看右侧excel中的参考表,其中有检查数字,范围为0到9。很酷,很高兴您找到了解决方案。
SET NOCOUNT ON;
DECLARE @check_digits TABLE (
    [transfer] INT,
    d0 INT,
    d1 INT,
    d2 INT,
    d3 INT,
    d4 INT,
    d5 INT,
    d6 INT,
    d7 INT,
    d8 INT,
    d9 INT,
    check_digit INT);
INSERT INTO @check_digits SELECT 0,0,9,4,6,8,2,7,1,3,5,0;
INSERT INTO @check_digits SELECT 1,9,4,6,8,2,7,1,3,5,0,9;
INSERT INTO @check_digits SELECT 2,4,6,8,2,7,1,3,5,0,9,8;
INSERT INTO @check_digits SELECT 3,6,8,2,7,1,3,5,0,9,4,7;
INSERT INTO @check_digits SELECT 4,8,2,7,1,3,5,0,9,4,6,6;
INSERT INTO @check_digits SELECT 5,2,7,1,3,5,0,9,4,6,8,5;
INSERT INTO @check_digits SELECT 6,7,1,3,5,0,9,4,6,8,2,4;
INSERT INTO @check_digits SELECT 7,1,3,5,0,9,4,6,8,2,7,3;
INSERT INTO @check_digits SELECT 8,3,5,0,9,4,6,8,2,7,1,2;
INSERT INTO @check_digits SELECT 9,5,0,9,4,6,8,2,7,1,3,1;

DECLARE @offset TABLE (
    id INT,
    offset INT);
INSERT INTO @offset
SELECT 1, 9
UNION ALL
SELECT 2, 6
UNION ALL
SELECT 3, 9
UNION ALL
SELECT 4, 9
UNION ALL
SELECT 5, 1
UNION ALL
SELECT 6, 0
UNION ALL
SELECT 7, 0
UNION ALL
SELECT 8, 0
UNION ALL
SELECT 9, 0
UNION ALL
SELECT 10, 0
UNION ALL
SELECT 11, 0
UNION ALL
SELECT 12, 3
UNION ALL
SELECT 13, 0
UNION ALL
SELECT 14, 0
UNION ALL
SELECT 15, 0
UNION ALL
SELECT 16, 0
UNION ALL
SELECT 17, 2
UNION ALL
SELECT 18, 0
UNION ALL
SELECT 19, 1
UNION ALL
SELECT 20, 8
UNION ALL
SELECT 21, 3
UNION ALL
SELECT 22, 0
UNION ALL
SELECT 23, 0
UNION ALL
SELECT 24, 0
UNION ALL
SELECT 25, 8
UNION ALL
SELECT 26, 7;

DECLARE @transfer INT = 0;
DECLARE @offset_value INT;
DECLARE @iterations INT = 1;
WHILE @iterations <= 26
BEGIN
    SELECT @offset_value = offset + 2 FROM @offset WHERE id = @iterations;
    SELECT @transfer = 
        CASE
            WHEN @offset_value = 2 THEN d0
            WHEN @offset_value = 3 THEN d1
            WHEN @offset_value = 4 THEN d2
            WHEN @offset_value = 5 THEN d3
            WHEN @offset_value = 6 THEN d4
            WHEN @offset_value = 7 THEN d5
            WHEN @offset_value = 8 THEN d6
            WHEN @offset_value = 9 THEN d7
            WHEN @offset_value = 10 THEN d8
            WHEN @offset_value = 11 THEN d9
        END
    FROM 
        @check_digits
    WHERE
        [transfer] = @transfer;
    SELECT @iterations = @iterations + 1;
END;
PRINT 'Check Digit is ' + CONVERT(CHAR(1), 10 - @transfer);
SET NOCOUNT OFF;
CREATE FUNCTION dbo.CheckDigit (
    @long_number VARCHAR(50))
RETURNS INT
AS
BEGIN
    --Hardcoded check digits
    DECLARE @check_digit INT;
    DECLARE @check_digits TABLE (
        [transfer] INT,
        d0 INT,
        d1 INT,
        d2 INT,
        d3 INT,
        d4 INT,
        d5 INT,
        d6 INT,
        d7 INT,
        d8 INT,
        d9 INT,
        check_digit INT);
    INSERT INTO @check_digits SELECT 0,0,9,4,6,8,2,7,1,3,5,0;
    INSERT INTO @check_digits SELECT 1,9,4,6,8,2,7,1,3,5,0,9;
    INSERT INTO @check_digits SELECT 2,4,6,8,2,7,1,3,5,0,9,8;
    INSERT INTO @check_digits SELECT 3,6,8,2,7,1,3,5,0,9,4,7;
    INSERT INTO @check_digits SELECT 4,8,2,7,1,3,5,0,9,4,6,6;
    INSERT INTO @check_digits SELECT 5,2,7,1,3,5,0,9,4,6,8,5;
    INSERT INTO @check_digits SELECT 6,7,1,3,5,0,9,4,6,8,2,4;
    INSERT INTO @check_digits SELECT 7,1,3,5,0,9,4,6,8,2,7,3;
    INSERT INTO @check_digits SELECT 8,3,5,0,9,4,6,8,2,7,1,2;
    INSERT INTO @check_digits SELECT 9,5,0,9,4,6,8,2,7,1,3,1;

    --Make the long number into an indexed list
    DECLARE @offset TABLE (
        id INT IDENTITY(1,1),
        offset INT);
    DECLARE @len INT;
    SELECT @len = LEN(@long_number);
    DECLARE @pos INT = 1;
    WHILE @pos <= @len
    BEGIN
        INSERT INTO @offset (offset) SELECT CONVERT(INT, SUBSTRING(@long_number, @pos, 1));
        SELECT @pos = @pos + 1;
    END;

    --Use recursive CTE
    WITH cte1 AS (
        SELECT
            1 AS iterations,
            offset,
            offset + 2 AS new_offset
        FROM
            @offset
        WHERE
            id = 1
        UNION ALL
        SELECT
            iterations + 1 AS iterations,
            o.offset,
            o.offset + 2 AS new_offset
        FROM
            cte1 c
            INNER JOIN @offset o ON o.id = c.iterations + 1
        WHERE
            c.iterations <= @len),
    cte2 AS (
        SELECT
            1 AS iterations,
            c.new_offset,
            CASE
                WHEN c.new_offset = 2 THEN d0
                WHEN c.new_offset = 3 THEN d1
                WHEN c.new_offset = 4 THEN d2
                WHEN c.new_offset = 5 THEN d3
                WHEN c.new_offset = 6 THEN d4
                WHEN c.new_offset = 7 THEN d5
                WHEN c.new_offset = 8 THEN d6
                WHEN c.new_offset = 9 THEN d7
                WHEN c.new_offset = 10 THEN d8
                WHEN c.new_offset = 11 THEN d9
            END AS [transfer]
        FROM 
            cte1 c
            INNER JOIN @check_digits cd ON cd.[transfer] = 0
        WHERE
            iterations = 1
        UNION ALL
        SELECT
            c.iterations + 1 AS iterations,
            c1.new_offset,
            CASE
                WHEN c1.new_offset = 2 THEN d0
                WHEN c1.new_offset = 3 THEN d1
                WHEN c1.new_offset = 4 THEN d2
                WHEN c1.new_offset = 5 THEN d3
                WHEN c1.new_offset = 6 THEN d4
                WHEN c1.new_offset = 7 THEN d5
                WHEN c1.new_offset = 8 THEN d6
                WHEN c1.new_offset = 9 THEN d7
                WHEN c1.new_offset = 10 THEN d8
                WHEN c1.new_offset = 11 THEN d9
            END AS [transfer]
        FROM 
            cte2 c
            INNER JOIN @check_digits cd ON cd.[transfer] = c.[transfer]
            INNER JOIN cte1 c1 ON c1.iterations = c.iterations + 1
        WHERE
            c1.iterations <= @len)
    SELECT @check_digit = 10 - [transfer] FROM cte2 WHERE iterations = @len;
    RETURN @check_digit;
END;
GO
SELECT dbo.CheckDigit('96991000000300002018300087');
SELECT dbo.CheckDigit('96991000000300002018300086');
SELECT dbo.CheckDigit('96991000000300002018300085');