从表中查找缺失值

时间:2018-12-17 12:09:42

标签: sql sql-server tsql sql-server-2016

是否可以在varchar列中进行搜索。

我得到了一个名为x的表,其中名为par的行和数据位于:

150/RXRPR1/18/0020642
150/RXRPR1/18/0020640
150/RXRPR1/18/0020639
151/RXRPR1/18/0020638
151/RXRPR1/18/0020637
151/RXRPR1/18/0020636
151/RXRPR1/18/0020634

该行丢失

150/RXRPR1/18/0020641
151/RXRPR1/18/0020635

如何编写SQL语句来搜索表以搜索丢失的数据?

数据类型为varchar,我有权只在数据库中选择

3 个答案:

答案 0 :(得分:2)

您可以在数字的右边7个字符中使用经典间隙检测,并按剩余的14个字符进行划分。使用LEAD函数查找下一个记录的值,并检查当前值与下一个值之间的差是否大于1。这将检测到间隙,并且可以通过将当前值加1来计算间隙的开始和结束值,然后从下一个值中减去一个。像这样:

declare @t table(col varchar(50))
insert into @t(col) values
('150/RXRPR1/18/0020642'),
('150/RXRPR1/18/0020640'),
('150/RXRPR1/18/0020639'),
('151/RXRPR1/18/0020638'),
('151/RXRPR1/18/0020637'),
('151/RXRPR1/18/0020636'),
('151/RXRPR1/18/0020634')

SELECT
     gapStart = left([current], 14) + right('000000' + cast(cast(right([current], 7) as int) + 1 as varchar(10)), 7)
    ,gapEnd   = left([next], 14) + right('000000' + cast(cast(right([next], 7) as int) - 1 as varchar(10)), 7)
FROM
(
SELECT
    [current] = col
   ,[next]    = LEAD(col) OVER (partition by left(col, 14) ORDER BY col)
FROM @t
) tmp
WHERE cast(right([next], 7) as int) - cast(Right([current], 7) as int) > 1;

答案 1 :(得分:0)

这个想法很简单。查找每个“前缀”的最小和最大数字,并与数字表结合以生成最小和最大之间的数字。寻找差距是微不足道的。请注意,如果间隙大于1,则可以使用。在642和649之间,有6个缺失值,将全部找到它们:

DECLARE @t TABLE(paragon VARCHAR(40));
INSERT INTO @t VALUES
('150/RXRPR1/18/0020642'),
('150/RXRPR1/18/0020640'),
('150/RXRPR1/18/0020639'),
('151/RXRPR1/18/0020638'),
('151/RXRPR1/18/0020637'),
('151/RXRPR1/18/0020636'),
('151/RXRPR1/18/0020634'),
('999/RXRPR1/18/0000001'),
('999/RXRPR1/18/0000010');

WITH minmax(prefix, min, max) AS (
    SELECT SUBSTRING(paragon, 1, 14)
         , MIN(CAST(SUBSTRING(paragon, 15, 7) AS INT))
         , MAX(CAST(SUBSTRING(paragon, 15, 7) AS INT))
    FROM @t
    GROUP BY SUBSTRING(paragon, 1, 14)
), numbers AS (
    SELECT TOP 1000 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS number
    FROM sys.all_objects
), result(missing) AS (
    SELECT prefix + FORMAT(min + number, '0000000')
    FROM minmax
    INNER JOIN numbers ON number <= (max - min)
    LEFT JOIN @t AS t ON prefix + FORMAT(min + number, '0000000') = paragon
    WHERE paragon IS NULL
)
SELECT *
FROM result

Demo on DB Fiddle

答案 2 :(得分:0)

您可以尝试以下查询:

请用相应的值替换@ MINVAL,@ MAXVAL。

declare @t table([VALUE] varchar(50))
insert into @t([VALUE]) values
('150/RXRPR1/18/0020642'),
('150/RXRPR1/18/0020640'),
('150/RXRPR1/18/0020639'),
('151/RXRPR1/18/0020638'),
('151/RXRPR1/18/0020637'),
('151/RXRPR1/18/0020636'),
('151/RXRPR1/18/0020634')

DECLARE @MINVAL INT = 20634, 
        @MAXVAL INT = 20642; 

WITH cte 
     AS (SELECT @MINVAL VAL 
         UNION ALL 
         SELECT val + 1 VAL 
         FROM   cte 
         WHERE  val < @MAXVAL) 
SELECT missing 
FROM   (SELECT *, 
               Replace (Lead([VALUE]) OVER ( ORDER BY val)
               , CONVERT (INT, RIGHT (Lead([VALUE]) OVER (ORDER BY val), 7)), 
               val) 
               MISSING 
        FROM   cte 
               LEFT JOIN @t X 
                      ON CONVERT (INT, RIGHT (X.[VALUE], 7)) = cte.val) X 
WHERE  [VALUE] IS NULL OPTION ( MAXRECURSION  10000)