如何在列中查找连续值

时间:2015-04-10 22:59:06

标签: sql oracle

我被赋予此任务以尝试检测具有大量行的表中的一些重复记录。该表包括2个连接表。所以首先我要:

select 
b.event_number_id, b.tenure_number_id, a.work_start_date, a.work_stop_date, a.amount
from
MTA.mta_sow_event a, mta_tenure_event_xref b
where
a.event_number_id = b.event_number_id

现在我们有一张工作表。重复记录具有唯一的event_number_id,重新定义的字段将包含相同的数据,如下所示:

| event_number_id |  tenure_number_id | work_start_date | work_stop_date |amount|
|-----------------|-------------------|-----------------|----------------|------|
|  5532733        | 688203            |     01-SEP-14   |  25-SEP-14     | 5000 |
|  5532734        | 688203            |     01-SEP-14   |  25-SEP-14     | 5000 |

所以,这是一个重复记录的例子。存在连续的event_number_id,并且所有剩余的列具有相同的信息。我们相信我们的系统已经创建了一段时间的重复事件(这不应该发生),所以我想查询整个连接表并查找具有完全相同数据但行不同的行的任何内容和连续的事件编号。

到目前为止,我设法做了一个简单的查询,向我显示任何具有相同信息的行,不包括event_number_id列:

select 
b.tenure_number_id, a.work_start_date, a.work_stop_date, a.amount, count(*)
from
MTA.mta_sow_event a, mta_tenure_event_xref b
where
a.event_number_id = b.event_number_id
group by
b.tenure_number_id, a.work_start_date, a.work_stop_date, a.amount
having
count(*) > 1

返回:

|  tenure_number_id | work_start_date | work_stop_date |amount|Count(*)|
|-------------------|-----------------|----------------|------|--------|
| 688203            |     01-SEP-14   |  25-SEP-14     | 5000 |   2    |
问题是,有时会有一些行具有相同的数据,但可能是有效的,所以我们此时可以做的最好的事情就是找到任何具有连续event_number_id的匹配行。这是我挂断电话的地方。有没有办法只拉出包含这些连续数字的行?

3 个答案:

答案 0 :(得分:1)

一般想法:对具有相同值(partition by tenure_number_id, work_start_date, work_end_date, amount)的行进行分组,为每个组找到最小event_number_id,从零开始查找组内event_number_id的行号(使用分析函数{{ 1}}和min),然后将最小ID和行号的总和与row_number进行比较。对于连续数字,它们必须相等:

event_number_id

答案 1 :(得分:1)

这是一种基于数据集连接的方法:

with cte_base_data as (
  select 
     ... your query here ...)
select 
from cte_base_data t1 join
     cte_base_data t2 on (t1.tenure_number_id = t2.tenure_number_id and
                          t1.work_start_date  = t2.work_start_date  and
                          t1.work_stop_date   = t2.work_stop_date   and
                          t1.amount           = t2.amount)
where t1.event_number_id = t2.event_number_id - 1;

效率取决于几个因素,例如扫描基表的效率和数据集的大小。

看到此方法的执行计划与分析函数方法的比较会很有趣。这种基于公式表的表达式连接应该非常高效,因为它依赖于散列连接,只要它们保留在内存中就几乎没有成本(这是一个很大的问号)。

如果event_number_id不是连续的话,我倾向于去分析函数 - 例如,如果可能存在间隙,那么作为连接将更难实现。鉴于其中一个是另一个递增的,我认为值得在加入时采取行动。

答案 2 :(得分:0)

您可以使用分析函数LAG and LEAD

SQLFiddle

with t as (
select event_number_id eid, b.tenure_number_id tid, 
    a.work_start_date d1, a.work_stop_date d2, a.amount amt
  from mta_sow_event a join mta_tenure_event_xref b using (event_number_id) )
select eid event_number_id, tid tenure_number_id, 
    d1 work_start_date, d2 work_stop_date, amt amount
  from (
    select t.*, 
        lag(eid) over (partition by tid, d1, d2, amt order by eid) l1, 
        lead(eid) over (partition by tid, d1, d2, amt order by eid) l2
      from t )
  where eid in (l1+1, l2-1) order by eid, tid