2015-11-02 67 views
0

我正试图在表格中查找丢失或“跳过”的值。这是我的表格的一个例子。在更改数字范围中查找缺失值

| Country  | U | Date  | 
| USA   | 1 | 1/1/2015 | 
| USA   | 2 | 2/1/2015 | 
| USA   | 3 | 3/1/2015 | 
| USA   | 5 | 5/1/2015 | 
| USA   | 6 | 6/1/2015 | 
| USA   | 7 | 7/1/2015 | 
| USA   | 8 | 8/1/2015 | 
| USA   | 9 | 9/1/2015 | 
| Germany  | 2 | 4/1/2015 | 
| Germany  | 3 | 5/1/2015 | 
| Germany  | 4 | 6/1/2015 | 
| Germany  | 5 | 7/1/2015 | 
| Germany  | 6 | 8/1/2015 | 
| Germany  | 7 | 9/1/2015 | 
| Canada  | 1 | 3/1/2015 | 
| Canada  | 2 | 4/1/2015 | 
| Canada  | 3 | 6/1/2015 | 
| Canada  | 4 | 7/1/2015 | 

有几件事我需要找到哪些可能会导致两个不同的查询,这是可以的。

首先,按国家进行分组并按USA进行筛选后,您会发现U列从1-9开始,但缺少U = 4以及与该行相对应的月份为4/1/2015。

其次,按国家进行分组并按德国筛选时,您会发现U列缺少U = 1的第一条记录,并且相应日期为3/1/2015。

然后最后根据国家进行分组并按加拿大进行过滤时,您会发现U列具有顺序排序,但日期列缺失一个月 - 2015/1/1。

我试过LAG()LEAD()方法,但似乎不工作,因为我不能聚合U。有没有人解决这个问题?

+0

你可以拥有的最大“U”是多少? –

+0

那么你的预期结果是什么?你不能返回不存在的值 – Mihai

+0

@vkp最大U会是9.最大日期应该是今天的月份。 – gh0st

回答

0

我想你可以用cte's来构造数字和日期表,然后在left join的主表中找到缺失的记录。

with nums as (select 1 as num union all select 2 union all ... select 9) 
, dates as (select '01/01/2015' as dt union all select '02/01/2015'.. 
      select '12/01/2015') 
select n.num, t.country, d.dt 
from nums n 
left join tablename t on n.num = t.U 
left join dates d on d.dt = t.date 
where t.U is null or t.date is null 
0

好像你只是想找到失踪的几个月,而且U可以将其与一个整数比1更大,在这种情况下,你需要使用U找到这个失踪的日期开始时只是被忽略如果U已在1开始,那么这将会存在。

如果你需要在U找到缺失的数字,这将不得不进行修改,因为它只关注缺失的日期。

鉴于数据:

declare @data table (Country varchar(10), U int, [Date] date) 

insert into @data values 
('USA', 1, '1/1/2015'), 
('USA', 2, '2/1/2015'), 
('USA', 3, '3/1/2015'), 
('USA', 5, '5/1/2015'), 
('USA', 6, '6/1/2015'), 
('USA', 7, '7/1/2015'), 
('USA', 8, '8/1/2015'), 
('USA', 9, '9/1/2015'), 
('Germany', 2, '4/1/2015'), 
('Germany', 3, '5/1/2015'), 
('Germany', 4, '6/1/2015'), 
('Germany', 5, '7/1/2015'), 
('Germany', 6, '8/1/2015'), 
('Germany', 7, '9/1/2015'), 
('Canada', 1, '3/1/2015'), 
('Canada', 2, '4/1/2015'), 
('Canada', 3, '6/1/2015'), 
('Canada', 4, '7/1/2015') 

您可以使用两个查询打造minmax日期为每个国家的列表,然后生成应该存在于每个国家的日期的完整列表。

select Country, dateadd(month, (-1 * min(U)) + 1, min([Date])) as min_Date, max([Date]) as max_Date 
into #min_max 
from @data 
group by Country 

;with cte (Country, [Date]) as (
    select Country, min_Date from #min_max 
    union all 
    select cte.Country, dateadd(month, 1, cte.Date) from #min_max t inner join cte on t.Country = cte.Country where cte.[Date] < t.max_Date 
) 
select * 
into #ranges 
from cte 

如果我们考察在#min_max#ranges数据,你会看到以下内容:

select * from #min_max 

Country min_Date max_Date 
---------- ---------- ---------- 
Canada  2015-03-01 2015-07-01 
Germany 2015-03-01 2015-09-01 
USA  2015-01-01 2015-09-01 

select * from #ranges order by 1, 2 

Country Date 
---------- ---------- 
Canada  2015-03-01 
Canada  2015-04-01 
Canada  2015-05-01 
Canada  2015-06-01 
Canada  2015-07-01 
Germany 2015-03-01 
Germany 2015-04-01 
Germany 2015-05-01 
Germany 2015-06-01 
Germany 2015-07-01 
Germany 2015-08-01 
Germany 2015-09-01 
USA  2015-01-01 
USA  2015-02-01 
USA  2015-03-01 
USA  2015-04-01 
USA  2015-05-01 
USA  2015-06-01 
USA  2015-07-01 
USA  2015-08-01 
USA  2015-09-01 

那么很简单找到#ranges没有在原始数据存在的记录:

select * 
from #ranges r 
where not exists (
     select 1 
     from @data d 
     where r.Country = d.Country 
      and r.[Date] = d.[Date] 
     ) 

Country Date 
---------- ---------- 
Germany 2015-03-01 
USA  2015-04-01 
Canada  2015-05-01 

然后我们放弃我们的临时表:

drop table #min_max, #ranges