2013-03-13 2 views
9

У меня есть таблица, в которой перечислены версии программного обеспечения, которые установлены: Выберите верхнюю 1 строку из каждой группы

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 

Я хотел бы, чтобы отобразить все поля одной записи от каждого userid, но только самый высокий версия (также версия varchar).

+1

Добро пожаловать в StackOverflow: если вы разместите код, XML или данные образцы ** ** PLEASE выделить те строки в текстовом редакторе и нажмите на кнопку «образцы кода» (' {} ') на панели инструментов редактора, чтобы красиво отформатировать и выделить синтаксис! –

+2

Также: *** SQL *** - это только * Structured Query Language * - язык, используемый многими системами баз данных, но ** не ** продукт базы данных. Многие вещи очень специфичны для вендора - поэтому было бы очень полезно узнать, что ** система баз данных ** (и какая версия) вы используете ... –

+0

Спасибо, Марк, я пытался выяснить, как отформатировать это когда вы его отредактировали. Версия SQL Server 12 – Easty

ответ

7

Вы не указали, как обрабатывать привязки, но это сделает это, если вы хотите, чтобы дубликаты отображались;

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.

Если вы хотите удалить дубликаты и если они существуют, выберите самый новый из них, вам придется немного расширить запрос;

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

Спасибо Joachim - я буду использовать ваш второй пример здесь - Paul – Easty

+0

@Easty Редактировал запрос немного, исключил некоторые приведения с общим выражением таблицы, чтобы облегчить глаза. –

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

Причина, по которой я удалил этот ответ, состоит в том, что сначала вы не упомянули сервер базы данных, который используете. кстати, это работает на sql server 2005 и выше ':)' –

+0

Версия - varchar ;-) –

8

При использовании SQL-сервера (минимум 2005), вы можете использовать CTE с функцией ROW_NUMBER. Вы можете использовать CAST для версии, чтобы получить правильный порядок:

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 возвращается всегда одна запись, даже если несколько пользователей с одинаковыми (вверху) версии. Если вы хотите вернуть все «топ-версии-пользовательские записи», вы должны заменить ROW_NUMBER на DENSE_RANK.

+0

Brilliant thanks – Easty

+1

+1 для указания 'DENSE_RANK()', который я никогда раньше не видел :) –

+0

+1 cte (и быстро) –

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

Я думаю, что это может решить вашу проблему:

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 

Я использовал функцию RANK для ур требования ....

0

Следующий код покажет, что вы хотите, и отлично подходит для выполнения!

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

Объяснение вашего кода было бы полезно не только для искателя, но и для будущих людей, которые могут наткнуться на это, чтобы найти решение той же проблемы. –

0

Если мой опыт настройки научил меня чему-либо, общие черты плохой плохой.

НО, если таблица, на которой вы получаете Top X, является большой (то есть сотни тысяч или миллионы). CROSS APPLY почти повсеместно лучший. На самом деле, если вы сравниваете это, перекрестная подача выполняет последовательно & замечательно в меньших масштабах также (в десятках тысяч) и когда-либо покрывает с галстуками Потенциальные требования.

Что-то вроде:

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 
) 
Смежные вопросы