2013-03-13 8 views
9

Mam tabeli, która zawiera listę wersje oprogramowania, które są zainstalowane: Wybierz górną 1 wiersz z każdej grupy

id | userid | version | datetime 
----+--------+---------+------------------------ 
111 | 75  | 10075 | 2013-03-12 13:40:58.770 
112 | 75  | 10079 | 2013-03-12 13:41:01.583 
113 | 78  | 10065 | 2013-03-12 14:18:24.463 
114 | 78  | 10079 | 2013-03-12 14:22:20.437 
115 | 78  | 10079 | 2013-03-12 14:24:01.830 
116 | 78  | 10080 | 2013-03-12 14:24:06.893 
117 | 74  | 10080 | 2013-03-12 15:31:42.797 
118 | 75  | 10079 | 2013-03-13 07:03:56.157 
119 | 75  | 10080 | 2013-03-13 07:05:23.137 
120 | 65  | 10080 | 2013-03-13 07:24:33.323 
121 | 68  | 10080 | 2013-03-13 08:03:24.247 
122 | 71  | 10080 | 2013-03-13 08:20:16.173 
123 | 78  | 10080 | 2013-03-13 08:28:25.487 
124 | 56  | 10080 | 2013-03-13 08:49:44.503 

Chciałbym, aby wyświetlić wszystkie pola jednego rekordu z każdego userid ale tylko najwyższa wersja (również wersja to varchar).

+1

Witamy StackOverflow: jeśli po przykłady kodu, XML lub danych, ** ** PROSZĘ wyróżnić te linie w edytorze tekstowym i kliknij przycisk „próbki kodu” (' {} ') na pasku narzędzi edytora, aby ładnie sformatować i podświetlić składnię! –

+2

Ponadto: *** SQL *** jest po prostu * Structured Query Language * - językiem używanym przez wiele systemów baz danych, ale ** nie ** produktem bazodanowym. Wiele rzeczy jest ściśle związanych z konkretnymi dostawcami - więc naprawdę dobrze byłoby wiedzieć, jaki ** system baz danych ** (i której wersji) używasz ... –

+0

Dzięki Mark, próbowałem wymyślić, jak sformatować to kiedy go edytowałeś. Wersja to serwer SQL 12 – Easty

Odpowiedz

7

Nie określasz sposobu obsługi powiązań, ale zrobi to, jeśli chcesz wyświetlać duplikaty;

SELECT a.* FROM MyTable a 
LEFT JOIN MyTable b 
    ON a.userid=b.userid 
AND CAST(a.version AS INT) < CAST(b.version AS INT) 
WHERE b.version IS NULL 

An SQLfiddle to test with.

Jeśli chcesz wyeliminować duplikaty i jeśli istnieją, wybierz najnowszy z nich, musisz nieco rozszerzyć zapytanie;

WITH cte AS (SELECT *, CAST(version AS INT) num_version FROM MyTable) 
SELECT a.id, a.userid, a.version, a.datetime 
FROM cte a LEFT JOIN cte b 
    ON a.userid=b.userid 
AND (a.num_version < b.num_version OR 
    (a.num_version = b.num_version AND a.[datetime]<b.[datetime])) 
WHERE b.version IS NULL 

Another SQLfiddle.

+0

Dzięki Joachimowi - będę używał twojego drugiego przykładu tutaj - Paul – Easty

+0

@Easty Edytował zapytanie nieznacznie, wyeliminował kilka rzutów ze zwykłą ekspresją tabeli, aby ułatwić to w oczach. –

6
WITH records 
AS 
(
    SELECT id, userid, version, datetime, 
      ROW_NUMBER() OVER (PARTITION BY userID 
           ORDER BY version DESC) rn 
    FROM tableName 
) 
SELECT id, userid, version, datetime 
FROM records 
WHERE RN =1 
+1

powodem, dla którego usunąłem tę odpowiedź, jest fakt, że na początku nie wspomniano o używanym serwerze bazy danych. przy okazji to działa na serwerze sql 2005 i wyżej ':)' –

+0

Wersja jest varcharem ;-) –

8

Jeśli używasz SQL Server (minimum 2005) można użyć CTE z funkcją ROW_NUMBER. Można użyć CAST wersji, aby uzyskać prawidłową kolejność:

WITH cte 
    AS (SELECT id, 
       userid, 
       version, 
       datetime, 
       Row_number() 
        OVER ( 
        partition BY userid 
        ORDER BY Cast(version AS INT) DESC) rn 
     FROM [dbo].[table]) 
SELECT id, 
     userid, 
     version, 
     datetime 
FROM cte 
WHERE rn = 1 
ORDER BY userid 

Demo

ROW_NUMBER powraca zawsze jeden rekord, nawet jeśli istnieje wielu użytkowników o tej samej wersji (u góry). Jeśli chcesz zwrócić wszystkie "rekordy użytkownika najwyższej wersji", musisz zastąpić ROW_NUMBER przez DENSE_RANK.

+0

Wspaniałe dzięki – Easty

+1

+1 za wskazanie 'DENSE_RANK()' której nigdy wcześniej nie widziałem :) –

+0

+1 cte są niesamowite (i szybkie) –

0
select l.* from the_table l 
left outer join the_table r 
on l.userid = r.userid and l.version < r.version 
where r.version is null 
0

myślę, że może to rozwiązać problem:

SELECT id, 
     userid, 
     Version, 
     datetime FROM (
      SELECT id, 
        userid, 
        Version, 
        datetime , 
        DENSE_Rank() over (Partition BY id order by datetime asc) AS Rankk 
      FROM [dbo].[table]) RS 
WHERE Rankk<2 

użyłem funkcji RANK ur wymogu ....

0

Poniższy kod wyświetli co chcesz i doskonale nadaje się do wykonania!

select * from the_table t where cast([version] as int) = 
(select max(cast([version] as int)) from the_table where userid = t.userid) 
+0

Objaśnienie kodu byłoby korzystne nie tylko dla pytającego, ale dla przyszłych ludzi, którzy mogą natknąć się na to, szukając rozwiązania tego samego problemu. –

0

Jeśli moje doświadczenie nauczyło mnie czegokolwiek, ogólniki są złe, złe.

ALE Jeśli tabela otrzymywania Top X z jest duża (czyli setki tysięcy lub miliony). CROSS APPLY jest prawie zawsze najlepsza. W rzeczywistości, jeśli porównujesz go, zastosowanie cross działa konsekwentnie zachwycająco również w mniejszej skali (w dziesiątkach tysięcy) I kiedykolwiek obejmuje potencjalne zapotrzebowanie na z wiązaniami.

Coś jak:

select 
    id 
    ,userid 
    ,version 
    ,datetime 
from 
    TheTable t 
cross apply 
(
    select top 1 --with ties 
     id 
    from 
     TheTable 
    where 
     userid = t.userid 
    order by 
     datetime desc 
)