在一次查询中查找文件名列表中缺失的数字

Find missing numbers in list of file names in one query

在文档管理数据库中有一个现有文件的列表。新文件应该有一个数字,例如 SW_01234.xxx。有一种为新号码服务的编号机制。问题是找到丢失的元素 - 例如文件是否被删除。

现有文件名可能完全不同并且不遵循上述方案。

我的尝试是这样做的:

  1. 在 "dot" 拆分现有文件 - 我不关心 .xxx 扩展名,例如 .doc、.xlsx

  2. 生成SW_00000到SW_99999的临时列表

  3. 引入b)中存在但a)中不存在的那些元素

样本值

..  
SW_00015.PRT  
SW_00016.DRW  
SW_00020.DRW  
SW_00020.PDF  
XBC115.DOC  
..  

我需要得到 SW_00017、SW_00018、SW_00019(不关心 XBC)

最后需要一个查询

这应该让您完成了 99% 的事情。根据需要进行调整。您会注意到输出中缺少记录 1、3、4 和 10。

DECLARE @allFiles TABLE (Name VARCHAR(100));
DECLARE @i INT = 0;
DECLARE @dataset TABLE (name VARCHAR(100));
INSERT INTO @dataset
        ( name )
VALUES  ( 'SW_00001.PRT'), ('SW_00003.DRW'), ('SW_00004.DRW'), ('SW_00010.PDF'
          );

WHILE @i < 100
BEGIN
    INSERT INTO @allFiles
            ( Name )
    VALUES  ( 'SW_' +  REPLICATE('0',5-LEN(@i)) + CAST(@i AS VARCHAR(10))  -- Name - varchar(100)
              );

    SET @i = @i + 1;
END;

SELECT *
FROM @allFiles af
WHERE NOT EXISTS (SELECT TOP 1 1 FROM @dataset ds WHERE af.Name = SUBSTRING(ds.name, 0, CHARINDEX('.', ds.name)))

我试图在一个查询中实现您的所有方法。为了在一个查询中完成所有操作,我使用 CTE 来隔离文档编号,并获取要在 "not exists" 部分中使用的编号范围。如果您需要数字 table 中的更多范围,您可以通过不同的查询来获取范围。参见 Generate Sequential Set of Numbers

declare @t as table (DocName varchar(50));

insert @t (DocName)
values 
('SW_00015.PRT')
,('SW_00016.DRW')
,('SW_00020.DRW')
,('SW_00020.PDF');


/*doing with CTE so the split and substring is more readable, plus needed it anyway for getting the numbers table*/
with isolatedFileNames
as (
    /*might be dots in filename, reversing it to isolate the last set (file ext)*/
    select DocName
        ,left(DocName, len(DocName) - charindex('.', reverse(DocName), 0)) as IsolatedDocName 
    from @t
    )
    ,isolatedNumbers
as (
    /*substring to get the number without the prefix*/
    select DocName
        ,IsolatedDocName
        ,cast(substring(IsolatedDocName, charindex('_', IsolatedDocName, 0) + 1, len(IsolatedDocName)) as int) as IsolatedDocNumber
    from isolatedFileNames
    )
    ,numbers
as (
    /*use row_number on a large set to get the range*/
    select ROW_NUMBER() over (
            order by object_id
            ) + (
            /*start at the first document number, change this to 0 if you want to start at 0*/
            select min(IsolatedDocNumber) - 1
            from isolatedNumbers
            ) as num
    from sys.all_objects
    )
    ,numbersLessThanDocNumbers
as (
    select num
    from numbers
    where num < (
            /*limit to max document number in the set*/
            select max(IsolatedDocNumber)
            from isolatedNumbers
            )
    )
select num as MissingFromDocumentSet
from numbersLessThanDocNumbers n
where not exists (
        select 1
        from isolatedNumbers iso
        where iso.IsolatedDocNumber = n.num
        )