[英]Oracle dedupe rows based on max values of 2 columns in conjunction
想知道是否有人知道使用Oracle SQL基於2個屬性的最大值共同對大型數據集中的記錄進行重復數據刪除的有效方法。
在下面的假設示例中,我希望通過首先選擇最大的transactionid來刪除所有重復的COMPANYID / CHILD ID對。 如果有效負載ID仍然有重復項,則為最大BATCHID。
注意:transactionID和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>
我的設想很簡單:1)在transactionid上使用max函數,然后對結果進行子查詢以最大達到batchID的最大值。2)將“重復數據刪除”集自動加入到原始集中以獲取產品信息
有人知道實現這一目標的更有效/更清潔的方法以及更好地處理null的方法嗎?
感謝任何反饋。
在Oracle 11g中,可以使用這種請求:
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
函數允許您處理空情況。 這是輸出(不適合您的輸出,但是我理解了您想要的是我的請求):
COMPANYID CHILDID MAX_TRANSACTIONID MAX_BATCHID MAX_PRODUCT_DETAILS
ABC EFG 306 54 Product2
ZXY BFG 407 Product3
編輯 :讓我嘗試進一步解釋DENSE_RANK
和LAST
:在GROUP BY
,此語法顯示為聚合函數(如SUM,AVG ...)。
ORDER BY
給出排序(此處為transactionid和batchid) DENSE_RANK LAST
指出您將專注於此排序的最后一個排(實際上可以有幾排具有相同的排位) MAX
在這些排名最高的行中取最大值。 在大多數情況下,您只有一行,因此MAX
可能看起來毫無用處,但事實並非如此。 因此,您經常會看到MIN
和DENSE_RANK FIRST
或MAX
和DENSE_RANK LAST
。 這是有關此主題的Oracle文檔 。
因為要處理多個列,所以還應該考慮僅使用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()
更快。 測試可以為您提供此信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.