如何查找给定范围的缺失记录?

时间:2013-06-28 14:04:53

标签: sql ms-access

我的下表如下

Country  Level      Code
USA      Level A    10
USA      Level A    11
USA      Level A    12
USA      Level A    13
USA      Level A    14
USA      Level B    20
USA      Level B    21
USA      Level B    22
USA      Level B    23
USA      Level B    24

Level      Min Code     Max Code
Level A    10           15
Level B    20           25

我需要查找表1是否具有表2中定义的范围之间的所有代码,如果缺少某些内容,我希望将其作为查询的输出。请帮忙

如果是以上示例A级15,则缺少B级25

2 个答案:

答案 0 :(得分:2)

这是一类可以通过使用“数字表”使用Access SQL解决的问题。这个“数字表”是您在Access中手动创建的表,其中包含一列数值(通常是顺序的),涵盖您将使用的一系列值。

(SQL语言的其他更复杂的实现允许我们“动态”创建这种表,但遗憾的是Access SQL不支持,所以我们必须事先创建表,手动或通过一些VBA代码。)

对于此示例,我们将使用名为[Numbers]的表,其中包含名为[n]的单个Number (Long Integer)字段。我们需要它覆盖[代码]值的整个预期范围,10到25,所以我们的[Numbers]表将如下所示:

 n
--
10
11
12
...
24
25

(请注意,如果“数字表”包含值预期范围之外通常无关紧要,因为使用它们的查询通常会限制某个WHERE子句中值的范围,但是“数字表”必须完全覆盖预期的值范围。)

一旦我们创建并填充了[Numbers]表,我们就可以从查询

开始
SELECT c.Country, c.Level, Numbers.n AS Code
FROM 
Numbers,
(SELECT DISTINCT [Country], [Level] FROM Codes) c 
INNER JOIN 
CodeRanges cr 
    ON c.Level=cr.Level
WHERE Numbers.n BETWEEN cr.[Min Code] AND cr.[Max Code]

返回规定范围内的所有可能代码

Country  Level    Code 
-------  -------  ----
USA      Level A    10
USA      Level A    11
USA      Level A    12
USA      Level A    13
USA      Level A    14
USA      Level A    15
USA      Level B    20
USA      Level B    21
USA      Level B    22
USA      Level B    23
USA      Level B    24
USA      Level B    25

现在我们可以通过使用上面的查询作为派生表(我称之为“AllCodes”)找到[Codes]表中缺少的列表中的项目:

SELECT [Country], [Level], [Code]
FROM 
    (
        SELECT c.Country, c.Level, Numbers.n AS Code
        FROM 
        Numbers,
        (SELECT DISTINCT [Country], [Level] FROM Codes) c 
        INNER JOIN 
        CodeRanges cr 
            ON c.Level=cr.Level
        WHERE Numbers.n BETWEEN cr.[Min Code] AND cr.[Max Code]
    ) AllCodes
WHERE NOT EXISTS
    (
        SELECT * FROM Codes
        WHERE Codes.Country=AllCodes.Country 
            AND Codes.Level=AllCodes.Level 
            AND Codes.Code=AllCodes.Code
    )

返回

Country  Level    Code
-------  -------  ----
USA      Level A    15
USA      Level B    25

答案 1 :(得分:1)

生成丢失的代码真的很痛苦,特别是在Access中。您需要一个包含所有可能代码的列表,然后找到不在该范围内的代码。在Access中生成这样的列表并不简单。

要查找是否缺少任何内容,您可以算一下:

select r.*
from ranges r left join
     (select level, count(distinct code) as NumCodes
      from t
     ) t 
     on r.level = t.level
where t.NumCodes < (r.MaxCode - r.MinCode)+1