2013-03-25 9 views
5

Przepraszamy za dwuznaczny tytuł, nie wiesz, jak szukać, lub zadaj to pytanie.Jak zwrócić pojedynczy wiersz na podstawie zagregowanej więcej niż jednej kolumny

Powiedzmy mamy TableA:

 
RowID  FkId  Rank  Date 
ID1   A   1   2013-3-1 
ID2   A   2   2013-3-2 
ID3   A   2   2013-3-3 
ID4   B   3   2013-3-4 
ID5   A   1   2013-3-5 

muszę utworzyć widok, który powróci 1 wiersz dla każdego FkId. Wiersz powinien mieć maksymalną rangę i maksymalną datę. Dla FkId "A" zapytanie zwróci wiersz "ID3".

Udało mi się zwrócić pojedynczy wiersz za pomocą podrzędnych zapytań; najpierw otrzymuję MAX (Rank), następnie dołączam do innego zapytania, które dostaje grupę MAX (Date) według FkId & Rank.

 
SELECT TableA.* 
(Select FkId, MAX(Rank) AS Rank FROM TableA GROUP BY FkId) s1 
INNER JOIN (Select FkId, Rank, MAX(Date) AS Date FROM TableA GROUP BY FkId,Rank) s2 ON s1.FkId = s2.FkId AND s1.Rank = s2.Rank 
INNER JOIN TableA ON s2.FkId = TableA.FkId AND s2.Rank = TableA.Rank AND s2.Date = TableA.Date 

Czy istnieje bardziej wydajne zapytanie, które zapewni takie same wyniki? Dzięki za spojrzenie.

Edytuj: Dodano ID5 od czasu ostatniej odpowiedzi. Gdybym spróbował normalnego MAX (pozycja), MAX (Data) GROUP BY FkId, to dla "A" dostałbym A; 2; 2013-3-5. Ten wynik nie byłby zgodny z identyfikatorem RowId.

+0

Jaki jest typ danych rangi? –

+0

Wiersz z datą maksymalną ze wszystkich wierszy z maksymalną pozycją? Lub wiersz z maksymalną pozycją ze wszystkich wierszy z maksymalną datą? (te dwa mogą się różnić!) –

+0

@AaronKurtzhals: numeric – csthopper

Odpowiedz

4

Można użyć ROW_NUMBER z CTE (zakładając sql-server> = 2005):

WITH CTE AS 
(
    SELECT TableA.*, 
     RN = ROW_NUMBER() OVER (PARTITION BY FkId Order By Rank Desc, Date DESC) 
    FROM Table A 
) 
SELECT RowID,FkId, Rank,Date 
FROM CTE WHERE RN = 1 
+1

+1. Funkcje okien są niesamowite. Możesz także użyć 'RANK()' zamiast 'ROW_NUMBER()' jeśli istnieje możliwość, że 2 lub więcej wierszy ma takie same 'FkId',' Rank' i 'Date'. –

+0

@ypercube: Jeśli chcę wszystkie max-wiersze, użyłbym 'DENSE_RANK' (jednak' RANK 'również tutaj, ponieważ nie ma żadnych przerw na pierwszej pozycji), ale OP powiedział, że chce" ... powrót jeden wiersz ". –

+0

Tak, ale nie powiedział nam, że jest gwarancja, że ​​jest tylko jedna. –

2

Twoje pytanie (wyjaśnione w komentarzach do tej odpowiedzi) prosi:

  1. Pojedynczy wiersz dla każdego FkId
  2. MAX Data i Rank
  3. Wyniki odpowiadać wierszowi w oryginalne dane.

W przypadku, gdy istnieją FkId z wierszami, w których maksymalna i maksymalna ranga znajdują się w osobnych wierszach, należy zrelaksować się przynajmniej w jednym z tych wymagań.

Jeśli jesteś gotów na relaks wymagania (3), a następnie można użyć GROUP BY:

SELECT FkId, MAX(Rank) AS Rank, Max(Date) AS Date 
FROM TableA 
GROUP BY FkId 

względu na dodatkową informację w komentarzach. Że chcesz najnowsza, z najwyżej ocenionych wpisów dla każdego FkId dodaje powinno działać:

SELECT FkId, Rank, MAX(Date) AS Date 
FROM TableA A 
WHERE Rank = (SELECT MAX(Rank) 
       FROM TableA sub 
       WHERE A.FkId = sub.FkId 
       GROUP BY sub.FkId) 
GROUP BY FkId, Rank 

Oto sqlfiddle to show it in action.

+0

'MAX (Rank)' i 'Max (Date)' nie mogą być w tym samym rzędzie! –

+0

Ale co, jeśli ID1 miał datę 2013-3-5? To zapytanie zwraca wartość A; 2; 2013-3-5, która nie jest zgodna z identyfikatorem RowId. – csthopper

+0

To jest uczciwa krytyka. Sądzę, że chciałbym kontratakować z "Czego spodziewasz się w takim razie?" Czy chcesz oba wiersze, czy nie? Zmieniłem moją odpowiedź, aby wyjaśnić jej ograniczenia i zakres pytania. – Wilduck

1

Można użyć Rank() i zapytań inline, aby go osiągnąć.


select * from TableA 
where RowID in (
     select rowID from (
      select FKID, RowID, 
        rank() over (partition by FKID order by [Rank] desc, [Date] desc) as RankNumber 
        from TableA) A 
     where A.RankNumber=1) 

SQL Fiddle Demo

0

Możesz być także podstępne i osiągnąć to, co ljh zasugerował like this:

select top 1 with ties * 
from TableA 
order by rank() over (
    partition by FKID 
    order by [Rank] desc, [Date] desc 
) 
Powiązane problemy