2009-11-23 3 views
2

J'ai une table avec l'ID INT et la date DATETIME, entre autres champs. Les lignes sont insérées dans cette table chaque jour de la semaine (non garanti), et plusieurs autres tables utilisent cet ID comme une clé étrangère.SQL Obtenir la date maximale dans l'ensemble de données pour chaque mois

Ma question est, comment puis-je obtenir l'id pour la date maximale de chaque mois, que je peux ensuite utiliser pour joindre à d'autres tables de données? Par exemple, si le processus a couru aujourd'hui, je voudrais voir les données pour le 31 janvier 28 février ... 31 oct 23 novembre

J'utilise SQL Server 2005.

Répondre

5
CREATE TABLE #foo (id INT, d DATETIME); 

INSERT #foo(id,d) SELECT 1, '20091101' 
UNION ALL SELECT 2, '20091102' 
UNION ALL SELECT 3, '20091006' 
UNION ALL SELECT 4, '20091001' 
UNION ALL SELECT 5, '20091002' 
UNION ALL SELECT 6, '20090904'; 

SELECT d, id 
FROM 
( 
    SELECT d, id, rn = ROW_NUMBER() OVER 
    (PARTITION BY DATEDIFF(MONTH, '20000101', d) 
    ORDER BY d DESC) 
    FROM #foo 
) AS x 
WHERE x.rn = 1 
ORDER BY x.d; 

DROP TABLE #foo; 
+0

Est-ce plus ou moins efficace que ce qui suit? SELECT * FROM (CHOISIR MOIS (d), MAX (d) DE #foo GROUPE PAR MOIS (d)) a JOIN #foo b ON ad = bd –

+0

Cela ne suffit pas, parce que maintenant vous combinez ce mois de novembre avec novembre dernier, et novembre avant cela, etc. MONTH() renvoie juste un entier (novembre = 11). –

+0

Votre requête ne fonctionne pas non plus, pour deux raisons: (a) il n'y a pas de colonne "d" dans la table dérivée "a" ... et (b) l'utilisation de MAX() suppose que l'identifiant est toujours incrémental . Que faire si vous réparez la table et régénérez les stats dans le mauvais ordre? Ma requête porte sur la date la plus élevée et non sur la plus grande clé de substitution. –

3

Cela va tirer le mois et l'année dernière et id:

SELECT month(date), year(date), max(id) 
FROM mytable 
GROUP BY month(date), year(date) 

et voici un script de test

create table #mytable (
date datetime, 
id int 
) 

insert into #mytable (date, id) values ('11/7/2009', 1) 
insert into #mytable (date, id) values ('11/8/2009', 2) 
insert into #mytable (date, id) values ('12/21/2009', 3) 
insert into #mytable (date, id) values ('12/30/2009', 4) 
insert into #mytable (date, id) values ('10/7/2009', 5) 
insert into #mytable (date, id) values ('10/12/2009', 6) 

SELECT month(date), year(date), max(id) 
FROM #mytable 
GROUP BY month(date), year(date) 

drop table #mytable 
1

Je sélectionneriez arrière la date maximale à l'aide d'un groupe par requête, comme ceci:

Select Year(datetimefield) as MyYear, month(datetimefield) as MyMonth max(day(datetimefield)) as MaxDate 
from table1 
group by Year(datetimefield), month(datetimefield) 

La requête ci-dessus vous donnera la date de transaction maximale pour chaque mois. Pour obtenir le maximum d'ID associé à cette date pour chaque mois, joignez les résultats de ce retour à la table source pour obtenir l'ID max pour ce jour.

Ainsi, votre requête complète ressemblerait à ceci:

select year(datetimefield) as MyYear, Month(datetimefield) as MyMonth, day(datetimefield), max(IdFieldName) as MaxID 
from someTable inner join 
    (select year(datetimefield) as MyYear, Month(datetimefield) as MyMonth,  max(day(datetimefield)) as MaxDate 
    from someTable 
    group by year(datetimefield), Month(datetimefield)) as innerSelect 
on innerselect.MyYear = year(datetimefield) and 
    innerselect.MyMonth = Month(datetimefield) and 
    innerselect.MaxDate = day(datetimefield) 
group by year(datetimefield), Month(datetimefield), day(datetimefield) 
+0

L'auto joignez-vous ici rendrait ce plus cher que d'utiliser les fonctions de fenêtre dans les autres réponses. –

+0

True, mais cette solution est également plus portable car elle ne dépend pas des fonctionnalités qui existent uniquement dans SQL2005 ou version ultérieure. –

+0

L'utilisateur a déclaré qu'il était sur SQL Server 2005, et je préférerais tirer parti des fonctionnalités disponibles plutôt que d'écrire un code SQL pur et peu performant dans l'événement impair que nous allons un jour passer à Oracle ou DB2. Ne va pas se produire, et est un scénario très rare ces jours-ci. En tout cas, à ce stade, la résolution de vos questions sera le moindre de vos soucis. –

2

Je suppose que vous voulez que le dernier jour du mois que vous avez un record (par exemple le 30 janvier, si vous avez. rien pour le 31 janvier).

SELECT 
    id, 
    date 
FROM (
    SELECT 
    id, 
    date, 
    ROW_NUMBER() OVER (PARTITION BY YEAR(date), MONTH(date) ORDER BY DAY(date) DESC) AS rowNum 
    FROM sometable 
) z 
WHERE rowNum = 1; 
+0

Celui-ci a fait l'affaire pour moi. OP, pourriez-vous expliquer l'utilisation de RowNumber? – Malavos

Questions connexes