2014-04-01 2 views
0

2 속성의 최대 값을 기준으로 Oracle SQL을 사용하여 대형 데이터 세트에서 레코드를 중복 제거하는 효과적인 방법을 아는 사람이 있는지 궁금합니다.오라클은 2 열의 최대 값을 기준으로 행을 중복 제거합니다.

아래 가상의 예에서 나는 최대 transactionid를 먼저 선택하여 모든 중복 된 COMPANYID/CHILD ID 쌍을 제거하려고합니다. 페이로드 ID에 여전히 중복이있는 경우 최대 BATCHID.

참고 : 트랜잭션

<p> CompanyID| ChildID | transactionid| BatchID | Product Details </P> 
<p> ABC   EFG  306     Product1 </p> 
<p>ABC   EFG  306   54  Product2</p> 
<p>ZXY   BFG  405   003  Product1</p> 
<p>ZXY   BFG  405   004  Product2</p> 
<p>ZXY   BFG  407     Product3</p> 

예상 결과 :

<p>ABC | EFG | 306 | 54 | Product 2 --selected on basis of highest transactionid and batchid </P> 
<p>ZXY | BFG | 405 | 407 | Product 3 --selected on basis of highest transactionid </p> 
는 TransactionId 및 일괄 ID는 (가장 낮은 값으로 예상되는) null 값

표가있을 수 있습니다

나는 envisione 단순히 D : 1)는 TransactionId에 최대 기능을 사용하고 이외에 "드 속아 '제품 정보를 얻기 위해 원래의 설정으로 설정하는

아무도 알고 있나요 가입 2) 자기를 최대 일괄 ID에 대한 결과를 subquerying 더 효율적이고 깨끗한 방법으로이를 달성하고 null을 더 잘 처리 할 수있는 방법을 찾고 있습니까?

의견을 보내주십시오.

오라클 11g에서

답변

2

, 당신은 요청의이 종류를 사용할 수 있습니다

with w(CompanyID, ChildID, transactionid, BatchID, Product_Details) as 
(
    select 'ABC', 'EFG', 306, null, 'Product1 ' from dual 
    union all 
    select 'ABC', 'EFG', 306, 54, 'Product2' from dual 
    union all 
    select 'ZXY', 'BFG', 405, 003, 'Product1' from dual 
    union all 
    select 'ZXY', 'BFG', 405, 004, 'Product2' from dual 
    union all 
    select 'ZXY', 'BFG', 407, null, 'Product3' from dual 
) 
select w.CompanyID, 
     w.ChildID, 
     max(w.transactionid) keep (dense_rank last order by nvl(w.transactionid, 0), nvl(w.batchid, 0)) max_transactionid, 
     max(w.batchid)   keep (dense_rank last order by nvl(w.transactionid, 0), nvl(w.batchid, 0)) max_batchid, 
     max(w.Product_Details) keep (dense_rank last order by nvl(w.transactionid, 0), nvl(w.batchid, 0)) max_Product_Details 
from w 
group by w.CompanyID, w.ChildID 
; 

nvl 기능을 사용하면 null이 사건을 처리 할 수 ​​있습니다. 다음은 출력 (당신에 맞지 않는,하지만 난 당신이 원하는 것을 이해로 내가 요청을 한) :

COMPANYID CHILDID MAX_TRANSACTIONID MAX_BATCHID MAX_PRODUCT_DETAILS 
ABC   EFG  306     54    Product2 
ZXY   BFG  407         Product3 

편집 : 나를 DENSE_RANKLAST 더 설명하려고하자하는 GROUP BY 내부에이 구문은 집계 함수 (예 : SUM, AVG ...)로 나타납니다. 그룹에서

  • 에서, ORDER BY가 (여기서,는 TransactionId 및 일괄 ID) 정렬 후
  • 이 분류의 마지막 위 행 (들)에 초점을 맞출 것이다 DENSE_RANK LAST 상태를 제공합니다 (당신은 참으로 여러 가지가있을 수 같은 순위의 행)
  • MAX은 최상위 순위 행에서 최대 값을 사용합니다. 대개의 경우 MAX은 쓸모없는 것처럼 보일 수 있으므로 한 행만 있습니다. 따라서 종종 MINDENSE_RANK FIRST 또는 MAXDENSE_RANK LAST이 표시됩니다.

여기는 the Oracle doc on this subject입니다. 여러 열을 처리하기 때문에

+0

감사합니다. 이전에 인용 한 사과는 잘못되었습니다. 귀하의 제안은 완벽하고 매우 빠르게 진행되었습니다. 마음에 들지 않으면 dense_ranking이 어떻게 작동하는지 설명해 주시겠습니까? 특히 max_product_details. 내가 이해하는 바로는 transaction_id와 batch_id를 기반으로 순위를 매기고 마지막 레코드 만 표시 (오름차순 - 따라서 최대)합니다. 이 기능은 내게는 외계인이기 때문에 나는 여전히 내 머리를 쥐고있다. 이것은 확실히 미래에 유용 할 것입니다! – user3484575

+0

환영합니다! 자세한 설명은 편집을 참조하십시오. – Emmanuel

1

, 당신은 또한 단지 row_number() 사용을 고려해야합니다 :

select t.* 
from (select t.*, 
      row_number() over (partition by CompanyId, ChildId 
           order by transactionid desc nulls last, BatchID desc nulls last 
           ) as seqnum 
     from t 
    ) t 
where seqnum = 1; 

keep/dense_rank 방법은 빠릅니다.여러 번 반복하는 것이 row_number()을 사용하는 것보다 빠르다는 것이 확실하지 않습니다. 테스트를 통해이 정보를 얻을 수 있습니다.

+0

'MAX'는'ASC' 정렬의 반대를 제안합니다. 또한 우선 순위에서 널값을 삭제하라는 요청은'ORDER BY transactionid DESC NULLS LAST'에서와 같이 동일한 명령문에서'NULLS LAST' 옵션으로 표현 될 수 있습니다. 이것은 좀 더 명시 적이며 db에 기본 동작이 무엇이든 관계가 있습니다. –

+1

@RichardPascual. . . 당신은 그 수에 맞고 질의가 수정되었습니다. 나는 실제로 여러개의'keep' 문과 비교하여이 성능이 어떻게 작동하는지에 대한 호기심이 궁금합니다. (나는 다른 대답을 upvoted.) –

관련 문제