Utilisation de Top dans SQL Server 2012

J'ai une table Contacts , parent à table Activity . Je voudrais sélectionner la dernière activité pour chaque contact, mais en obtenant plus d'une ligne.

C'est ma requête:

 select top 30 * from Contacts o, Activity d where o.ID = d.contact and d.ID > 401061 and Last_Action is null order by d.activity_date desc 

Je pense que j'ai besoin de Top? mais je ne sais pas comment mettre en œuvre ici. Toute aide serait appréciée.

Vous pouvez utiliser row_number() pour numéroter les activités de chaque contact. Dans une requête externe, vous pouvez filterr uniquement la dernière activité par contact:

 select top 30 * from ( select row_number() over ( partition by o.ID order by d.activity_date desc) as rn , * from Contacts o join Activity d on o.ID = d.contact where d.ID > 401061 and Last_Action is null ) as SubQueryAlias where rn = 1 -- Only last activity per contact order by activity_date desc 

Voici une façon d'utiliser not exists qui fonctionnera sur la plupart des dbs. Vous select essentiellement chaque activité par contact lorsqu'une nouvelle activité n'existe pas (c'est donc la dernière activité).

 select top 30 * from activity a join contact c on c.id = a.contact where not exists ( select 1 from activity b where b.contact = a.contact and b.activity_date > a.activity_date ) and last_action is null and a.id > 401061 order by a.activity_date desc 

C'est un peu de conjecture car je ne peux pas voir à quoi ressemblent vos arrays en termes de colonnes, mais peut-être que cela (ou quelque chose comme ça) fonctionnerait?

 select top 30 * from Contacts o, (SELECT contact, max(activity_date) FROM Activity GROUP BY contact) d where o.ID = d.contact And d.ID > 401061 and Last_Action is null order by d.activity_date desc 

Je pense que vous voulez utiliser une sous-requête:

 SELECT TOP 30 * FROM Contacts AS o, ( SELECT contact, MAX( activity_date ) AS activity_date FROM Activity WHERE contact > 401061 AND Last_Action IS NULL GROUP BY contact ) AS d WHERE o.ID = d.contact ORDER BY d.activity_date 

En supposant que vous voulez les 30 premières actions par contact, c'est exactement le genre de chose pour CROSS APPLY été inventé.

Quelque chose comme le suivant – les incertitudes sont parce que je ne peux pas voir un exemple de vos données.

 select * from contacts cross apply ( select top 30 * from activity where contacts.id = activity.contact and 401061 < activity.id ) as _ca where last_action is null -- Perhaps you could move this into the CA - but we don't know which table it's from order by activity.activity_date desc; 

modifier

 select top 30 * from contacts cross apply ( select top 1 * from activity where contacts.id = activity.contact and 401061 < activity.id order by activity.activity_date desc ) as _ca where last_action is null -- assuming this is in table contacts order by _ca.activity_date desc; 

Utiliser un cte

 WITH cte AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY contact ORDER BY activity_date DESC) rn FROM Activity WHERE d.ID > 401061 AND Last_Action IS NULL ) SELECT TOP 30 * FROM Contacts o JOIN cte d ON o.Id = d.contact WHERE d.rn = 1 ORDER BY cte.activity_date DESC