2010-10-29 6 views
5

J'ai une table commeComment puis-je obtenir plusieurs valeurs les plus élevées d'une table?

id f1 
-------------- 
1 2000-01-01 
1 2001-01-01 
1 2002-01-01 
1 2003-01-01 

Et je veux dire que les 3 dernières dates une ligne

CREATE TABLE Test 
(
    id INT NOT NULL, 
    f1 DATETIME NOT NULL, 
) 

INSERT INTO Test (id, f1) VALUES (1, '1/1/2000') 
INSERT INTO Test (id, f1) VALUES (1, '1/1/2001') 
INSERT INTO Test (id, f1) VALUES (1, '1/1/2002') 
INSERT INTO Test (id, f1) VALUES (1, '1/1/2003') 

SELECT T1.* FROM Test as T1 

tentais quelque chose comme

  SELECT T1.*,T2.* 
      FROM Test AS T1 
LEFT OUTER JOIN Test AS T2 ON T1.id = T2.id AND (T2.f1 > T1.f1) 
+3

Pourquoi doit-il être tous dans une ligne? Il serait beaucoup plus facile d'avoir une seule colonne. –

+1

Je pense qu'il est beaucoup plus logique de les renvoyer en tant que lignes, et non 1 rangée avec plusieurs colonnes. – dotariel

+0

Avez-vous besoin des trois dernières dates pour chaque identifiant? (J'ai remarqué que votre identifiant est toujours 1) –

Répondre

3

Dans SQL Server, vous pouvez le faire select top 3 * from Test order by f1 desc. D'autres années SGBD ont posibilités similaires tels que limit de MySql, Oracle, etc. rownum

+0

Cela ne fonctionnerait pas. Cela donnerait les 3 dernières dates dans une colonne. Maestro1024 demande les 3 dernières dates en une ligne. – pavanred

3

Bien que je ne suis pas sûr comment les obtenir dans une seule rangée, vous pouvez commencer avec:

SELECT * FROM Test ORDER BY f1 DESC LIMIT 3 

Cela devrait vous donner un résultat comme:

id f1 
1 2003-01-01 
1 2002-01-01 
1 2001-01-01 

Leur mise en une seule rangée, cependant, peut être un peu plus difficile ...

2

Vous pouvez le faire avec une combinaison de ORDER BY, TOP et PIVOT, au moins sur SQL Server. Il semble que beaucoup d'autres réponses aient ignoré la nécessité que le résultat soit "sur une seule ligne".

0

Vous pouvez obtenir les 3 premières dates d'affilée en faisant pivoter la table et en concaténant peut-être les dates si vous le souhaitez dans une colonne après le pivotement.

Editer: Voici une requête pour faire pivoter la table et fournir les 3 dernières dates d'affilée. Mais pour pivoter, vous devez connaître les données disponibles dans le tableau. Je me suis dit que puisque nous demandons les 3 dernières dates, nous ne connaîtrons pas les valeurs exactes pour pivoter autour de la colonne des dates. Donc d'abord, j'ai interrogé les 3 dernières dates dans une table temporaire. Puis couru un pivot sur le row_number 1, 2 et 3 pour obtenir les 3 dernières dates d'affilée.

Select Top 3 * into #Temp from Test order by f1 desc 

Maintenant, pivot sur la colonne row_number -

SELECT id,[3] as Latest,[2] as LatestMinus1,[1] as LatestMinus2 
FROM (
select ROW_NUMBER() OVER(ORDER BY f1) AS RowId,f1,id from #Temp) AS Src 
PIVOT (Max(f1) FOR RowId IN ([1],[2],[3])) AS pvt 

Il en résulte -

Id | Latest     |LatestMinus1    |LatestMinus2 
1 | 2003-01-01 00:00:00.000 | 2002-01-01 00:00:00.000 | 2001-01-01 00:00:00.000 

Et, bien sûr

drop table #Temp 
+0

Modifier: Ajout d'une requête à ma réponse. – pavanred

+0

Les analyses ne sont pas supportées par toutes les bases de données - SQL Server 2005+, Oracle 9i +, PostgreSQL 8.4 + ... mais pas MySQL –

0

Qu'en est-ce?

SELECT T1.f1 as "date 1", T2.f1 as "date 2", T3.f1 as "date 3" 
    FROM (SELECT * 
     FROM `date_test` 
     ORDER BY `f1` DESC 
     LIMIT 1) AS T1, 
     (SELECT * 
     FROM `date_test` 
     ORDER BY `f1` DESC 
     LIMIT 1, 1) AS T2, 
     (SELECT * 
     FROM `date_test` 
     ORDER BY `f1` DESC 
     LIMIT 2, 1) AS T3 
; 

qui sort:

+------------+------------+------------+ 
| date 1  | date 2  | date 3  | 
+------------+------------+------------+ 
| 2003-01-01 | 2002-01-01 | 2001-01-01 | 
+------------+------------+------------+ 

Le seul inconvénient est que vous avez besoin d'au moins trois rangées, sinon il ne retournera rien ...

En utilisant JOIN, vous pouvez le faire :

SELECT T1.id, 
     T1.f1 as "date 1", 
     T2.f1 as "date 2", 
     T3.f1 as "date 3" 
    FROM `date_test` as T1 
    LEFT JOIN (SELECT * FROM `date_test` ORDER BY `f1` DESC) as T2 ON (T1.id=T2.id AND T1.f1 != T2.f1) 
    LEFT JOIN (SELECT * FROM `date_test` ORDER BY `f1` DESC) as T3 ON (T1.id=T3.id AND T2.f1 != T3.f1 AND T1.f1 != T3.f1) 
GROUP BY T1.id 
ORDER BY T1.id ASC, T1.f1 DESC 

Qui va retourner quelque chose comme:

+----+------------+------------+------------+ 
| id | date 1  | date 2  | date 3  | 
+----+------------+------------+------------+ 
| 1 | 2001-01-01 | 2003-01-01 | 2002-01-01 | 
+----+------------+------------+------------+ 

L'inconvénient est que date1, date 2 et date 3 ne sera pas nécessairement dans un ordre spécifique (selon la sortie au-dessus de l'échantillon). Mais cela peut être réalisé par programme. Le côté positif est que vous pouvez insérer une clause WHERE avant le GROUP BY et vous pouvez effectuer une recherche par T1.id, par exemple.

1

dans T-SQL (Cela vous obtenir les trois dates top même si elles sont toutes la même valeur)

with TestWithRowNums(f1, row_num) as 
(
select f1, row_number() over(order by [f1] desc) as row_num from test 
) 
select 
(select [f1] from TestWithRowNums where row_num = 1) as [Day 1], 
(select [f1] from TestWithRowNums where row_num = 2) as [Day 2], 
(select [f1] from TestWithRowNums where row_num = 3) as [Day 3] 

Cela vous obtiendrez les trois dates DISTINCTS

with TestWithRankNums(f1, rank_num) as 
(
select f1, dense_rank() over(order by [f1] desc) as rank_num from test 
) 
select 
(select top 1 [f1] from TestWithRankNums where rank_num = 1) as [Day 1], 
(select top 1 [f1] from TestWithRankNums where rank_num = 2) as [Day 2], 
(select top 1 [f1] from TestWithRankNums where rank_num = 3) as [Day 3] 

Essayez cela dans SQL Server 2005

--to get top three values even if they are the same 
select [1] as Day1, [2] as Day2, [3] as Day3 from 
(select top 3 f1, row_number() over(order by [f1] desc) as row_num from test) src 
pivot 
(
max(f1) for row_num in([1], [2], [3]) 
) as pvt 
--to get top three distinct values 
select [1] as Day1, [2] as Day2, [3] as Day3 from 
(select f1, dense_rank() over(order by [f1] desc) as row_num from test) src 
pivot 
(
max(f1) for row_num in([1], [2], [3]) 
) as pvt 
+0

J'utilise MS SQL et cela ne fonctionne pas. La syntaxe est-elle correcte ou n'est-elle pas valide sur MS SQL? – Maestro1024

+0

@ Maestro1024, cela ne fonctionnerait que sur les nouvelles versions de SQl Server, mais il passe certainement la vérification de la syntaxe. – HLGEM

+0

@ Maestro1024, quelle version de MS SQL Server utilisez-vous? –