基于多个标识符删除除一行之外的所有行

时间:2013-07-26 15:35:44

标签: sql oracle

我有一张表TPAIE,2条信息:

  • numben(受益人人数)
  • datPai(我支付这个人的日期)

通常,对于一个约会,我必须有一个受益人(我支付一次约会的人)。然而,碰巧我有几行具有相同的受益人和相同的日期

    COUNTING NUMBEN   PERPAI 

     9 75005100 01/08/13 
     9 75005109 01/08/13 

我怎样才能删除所有这些线路,但每个线路的受益人和特定日期都有?

注意:我发现了类似的东西,但如果我只有一个标识符就可以了

delete from tpaie where numben not in 
(select min(numben) from tpaie group by numben, perpai);

注意2:我发现这个sql可以删除多次存在的所有行:我只是说'不要删除第一行'。在某个地方有一个rownum?

delete from tpaie a 
where (numben, perpai) in (
select numben, perpai from tpaie b where b.rowid <> a.rowid)      

2 个答案:

答案 0 :(得分:2)

第二次尝试,你离目标很近。您只需要了解rowid是唯一物理表行标识符的保留字。查看documentation了解详情。

查询:

delete tpaie 
where rowid not in (
  select distinct
    ( first_value(rowid) over (
        partition by numben, perpai order by rowid
      )
    ) first_row_id
  from 
    tpaie
)

您可以在this SQLFiddle中看到完整的测试。

<强>更新
@mlwacosmos找到了一个性能更好的变种。当然,原始答案中的not in不是一个好习惯。所以我添加了他的变体来回答以供将来参考:

delete from tpaie a 
where 
  rowid not in ( 
    select distinct 
      ( first_value(rowid) 
          over (partition by numben, perpai order by rowid) 
      ) first_row_id 
    from 
      tpaie b 
    where 
      a.numben = b.numben 
      and 
      a.perpai = b.perpai 
  ) 
  and 
  (numben, perpai) in ( select numben, perpai 
                        from tpaie b 
                        where b.rowid <> a.rowid 
                      )

SQLFiddle

但是此解决方案再次涉及not in,因此将in函数用于另一个分析排名可能会更好:

delete from tpaie a 
where 
  rowid in ( 
    select row_id 
    from (
      select 
        rowid row_id, 
        ( dense_rank() over ( -- enumerate rows
            partition by numben, perpai order by rowid
          )
        ) row_rank
      from 
        tpaie
    )  
    where
      row_rank > 1 -- eliminate rows ranked first
  )

SQLFiddle

答案 1 :(得分:0)

使用DISTINCT创建一个临时表,每个日期只获得一个条目,每个日期,删除主表中的所有条目,并使用临时表重新加载它,如:

SELECT DISTINCT numben, perpai 
INTO #temp
FROM tpaie

DELETE FROM tpaie

INSERT INTO tpaie
SELECT * FROM #temp

编辑:

对于特定日期,请尝试:

SELECT DISTINCT numben, perpai 
INTO #temp
FROM tpaie
WHERE perpai = '01/08/13'

DELETE FROM tpaie
WHERE perpai = '01/08/13'

INSERT INTO tpaie
SELECT * FROM #temp