2013-03-13 15 views
9

Ho una tabella che elenca le versioni del software che vengono installati: Selezionare la parte superiore 1 ferro a ogni gruppo

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 

Vorrei potrai vedere tutti i campi di un record da ogni userid ma solo la più alta versione (anche la versione è una varchar).

+1

Benvenuti a StackOverflow: se pubblichi esempi di codice, XML o di dati, ** NOTA ** evidenziare quelle righe nell'editor di testo e fare clic sul pulsante "esempi di codice" (' {} ') sulla barra degli strumenti dell'editor per formattarlo in modo appropriato e la sintassi evidenziarlo! –

+2

Inoltre: *** SQL *** è solo * Structured Query Language * - una lingua utilizzata da molti sistemi di database, ma ** non ** un prodotto di database. Un sacco di cose sono altamente specifiche del fornitore - quindi sarebbe molto utile sapere che sistema di database ** ** (e quale versione) stai usando .... –

+0

Grazie Mark, stavo cercando di capire come formattare quando lo hai modificato. La versione è SQL Server 12 – Easty

risposta

7

Non si specifica come si desidera gestire i legami, ma lo farà se si desidera visualizzare i duplicati;

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.

Se si desidera eliminare i duplicati e se esistono selezionarne uno nuovo, sarà necessario estendere la query;

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

Grazie Joachim - Userò il tuo secondo esempio qui - Paul – Easty

+0

@Easty Modifica leggermente la query, eliminando alcuni calchi con un'espressione di tabella comune per renderlo più facile agli occhi. –

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

il motivo per cui ho eliminato questa risposta è perché all'inizio non hai menzionato il server del database che stai utilizzando. dal modo in cui questo funziona su SQL Server 2005 e successivi ':)' –

+0

La versione è un varchar ;-) –

8

Se si utilizza SQL-Server (minimo 2005) è possibile utilizzare un CTE con la funzione ROW_NUMBER. È possibile utilizzare CAST per la versione per ottenere l'ordine corretto:

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 restituisce sempre un record, anche se ci sono più utenti con la stessa versione (in alto). Se si desidera restituire tutti i "record utente versione superiore", è necessario sostituire ROW_NUMBER con DENSE_RANK.

+0

Grazie brillante – Easty

+1

+1 per indicare 'DENSE_RANK()' che non ho mai visto prima :) –

+0

+1 cte sono fantastici (e veloci) –

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

Penso che questo possa risolvere il problema:

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 

funzione RANGO ho usato per ur requisito ....

0

Il seguente codice mostrerà ciò che si vuole ed è ottimo per le prestazioni!

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

Una spiegazione del tuo codice sarebbe vantaggiosa non solo per il richiedente, ma per le persone future che potrebbero imbattersi in questa ricerca di una soluzione allo stesso problema. –

0

Se la mia esperienza di messa a punto mi ha insegnato qualcosa, le generalità sono male cattive.

MA, se il tavolo si ottiene il Top X è grande (vale a dire centinaia di migliaia o milioni). CROSS APPLY è quasi universalmente il migliore. Infatti, se lo fai un benchmark, cross applica performs coerentemente & in modo egregio anche a dimensioni ridotte (in decine di migliaia) E copre sempre il con il requisito di vincoli.

Qualcosa di simile:

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 
) 
Problemi correlati