SQL для возврата отдельных строк с максимальным значением столбца? Осложняется дубликатами любого другого столбца

#duplicates #subquery #distinct

#дубликаты #подзапрос #distinct

Вопрос:

У меня есть 1 таблица, она содержит 6 столбцов (DivisionId, ItemId, BuyerCode, BuyerName, ReceivedPounds, POIssueDate), и все 6 не уникальны. Мое ОТДЕЛЬНОЕ значение, которое я в конечном итоге хочу, — это КОНКАТ DivisionID_ItemId . Я уже предпринял много попыток, я хочу вернуть каждую уникальную строку DivisionId и ItemId и BuyerCode с наибольшим количеством фунтов для этой комбинации DivisionId ItemId. Моя сложность в том, что у меня есть несколько кодов покупателя для большинства идентификаторов элементов, и у меня есть несколько идентификаторов элементов для разных идентификаторов подразделений. Я приблизился, но мой конечный результат по-прежнему дает мне каждого покупателя для каждого товара. Вот мой текущий запрос в SSMS. Я самоучка, поэтому не стесняйтесь, я пытался вырваться из каждого подзапроса. T1 суммирует фунты, FT — максимальная функция, T2 — объединить покупателя с MAX div и item. Проблема в том, что я все еще получаю несколько вхождений divisionId и ItemId в моем результате. Мне не хватает способа сделать результат таким же отличным, как подзапрос FT.

     SELECT FT.DivisionId,FT.ItemId, T2.BuyerCode, T2.BuyerName
FROM(   SELECT DISTINCT T1.DivisionId,T1.ItemId, MAX(T1.SUMPOUNDS) as MaxPounds
        FROM(   SELECT DISTINCT TCO.DivisionId, TCO.ItemId, TCO.BuyerCode, TCO.BuyerName, SUM(TCO.ReceivedPounds) as SUMPOUNDS 
                FROM [GTDev].[dbo].[TCO_FinalData_ABC] TCO
                WHERE PO_Issue_Date > (GETDATE()-90) AND ReceivedPounds > 0
                GROUP BY TCO.DivisionId, TCO.ItemId, TCO.BuyerCode, TCO.BuyerName) as T1
        GROUP BY T1.DivisionId,T1.ItemId) as FT
LEFT JOIN ( SELECT DISTINCT T2.DivisionId, T2.ItemId, T2.BuyerCode, T2.BuyerName, SUM(T2.ReceivedPounds) as SUMPOUNDS
            FROM [GTDev].[dbo].[TCO_FinalData_ABC] T2
            WHERE PO_Issue_Date > (GETDATE()-90) AND ReceivedPounds > 0
            GROUP BY T2.DivisionId, T2.ItemId, T2.BuyerCode, T2.BuyerName) as T2
ON FT.DivisionId = T2.DivisionId AND FT.ItemId = T2.ItemId AND FT.MaxPounds = T2.SUMPOUNDS
GROUP BY FT.DivisionId,FT.ItemId, T2.BuyerCode, T2.BuyerName
  

TL; DR — необходимо суммировать фунты для каждого уникального DivId, ItemId, Buyer, а затем выбрать МАКСИМАЛЬНОЕ количество фунтов для каждого DivId и ItemId и вернуть Покупателю наибольшее количество фунтов для каждой комбинации DivId ItemId.

Заранее спасибо! Не стесняйтесь говорить мне, что не так, и не переписывать код, если вы этого не хотите. Не ищу кого-то, кто выполнит мою работу, просто совет, чтобы решить эту проблему!

Ответ №1:

Я бы создал идентификатор с DivId и ItemId, например:

 select DivId||'_'||ItemId as indicator, {other columns} from {your tables and conditions}
  

Затем я бы запустил запрос поверх него, например:

 select sum(pounds), indicator, buyer from ({the previous query})
group by indicator,buyer, then select the max, and rank it (this is the trick that you are missing)
  

Посмотрите на всю эту последовательность, я думаю, это то, что вам нужно: (Я разбил это на несколько частей, вы можете упростить это или сделать так)

   select * from (
 select distinct indicator, max(ReceivedPoundsSum), BuyerCode,RANK() OVER ( PARTITION BY indicator ORDER BY max(ReceivedPoundsSum) DESC ) AS "Rank" from (
select sum(ReceivedPounds) ReceivedPoundsSum, indicator, BuyerCode,BuyerName from (
 with data as(
 select 1 DivisionId, 1 ItemId,1 BuyerCode,'user1' BuyerName,55 ReceivedPounds,sysdate POIssueDate from dual union
 select 1 DivisionId, 1 ItemId,3 BuyerCode,'user3' BuyerName,15 ReceivedPounds,sysdate POIssueDate from dual union
 select 2 DivisionId, 2 ItemId,1 BuyerCode,'user1' BuyerName,25 ReceivedPounds,sysdate POIssueDate from dual union
 select 2 DivisionId, 2 ItemId,2 BuyerCode,'user2' BuyerName,35 ReceivedPounds,sysdate POIssueDate from dual union
 select 2 DivisionId, 2 ItemId,3 BuyerCode,'user3' BuyerName,45 ReceivedPounds,sysdate POIssueDate from dual union
 select 3 DivisionId, 3 ItemId,5 BuyerCode,'user5' BuyerName,55 ReceivedPounds,sysdate POIssueDate from dual union
 select 1 DivisionId, 3 ItemId,3 BuyerCode,'user3' BuyerName,5 ReceivedPounds,sysdate POIssueDate from dual union
 select 4 DivisionId, 4 ItemId,4 BuyerCode,'user4' BuyerName,1 ReceivedPounds,sysdate POIssueDate from dual union
 select 5 DivisionId, 4 ItemId,4 BuyerCode,'user4' BuyerName,12 ReceivedPounds,sysdate POIssueDate from dual union
 select 6 DivisionId, 5 ItemId,4 BuyerCode,'user4' BuyerName,13 ReceivedPounds,sysdate POIssueDate from dual union
 select 6 DivisionId, 5 ItemId,1 BuyerCode,'user1' BuyerName,14 ReceivedPounds,sysdate POIssueDate from dual union
 select 6 DivisionId, 6 ItemId,2 BuyerCode,'user2' BuyerName,16 ReceivedPounds,sysdate POIssueDate from dual union
 select 5 DivisionId, 10 ItemId,1 BuyerCode,'user1' BuyerName,157 ReceivedPounds,sysdate POIssueDate from dual)
 select DivisionId||'_'||ItemId as indicator,a.* from data a
 ) group by indicator, BuyerCode,BuyerName
 ) group by indicator, BuyerCode 
 ) where "Rank"=1
  

Результат будет выглядеть так:

введите описание изображения здесь

Надеюсь, это поможет!