2017-05-17 3 views
2

J'ai des données qui ont des dates ValidFrom et ValidTo associées. En termes simples:T-SQL - Suivre les occurrences dans le temps

MembershipId | ValidFromDate | ValidToDate 
========================================== 
0001   | 1997-01-01 | 2006-05-09 
0002   | 1997-01-01 | 2017-05-12 
0003   | 2005-06-02 | 2009-02-07 

Il existe un index non cluster sur cette table qui inclut les deux dates en tant que valeurs clés.

J'ai également une table de dimension de date qui couvre chaque date de 1900 à 2999. J'essaie de comprendre comment je peux sélectionner une plage de dates du tableau de dimension Date (disons 2016-01-01 à 2016-12-31) puis d'identifier, pour chaque date, le nombre d'appartenances valides à cette date.

Le code ci-dessous fait le travail mais la performance n'est pas géniale et je me demandais si quelqu'un avait des recommandations pour une meilleure façon de faire?

SELECT 
    d.DateKey 
    ,(SELECT COUNT(*) FROM Memberships AS m 
    WHERE d.DateKey between m.ValidFromDateKey and m.ValidToDateKey 
    ) AS MembershipCount 

FROM  
    DIM.[Date] AS d 

WHERE 
    d.CalendarYear = 2016 

Merci d'avance pour vos suggestions!

Répondre

4

La logique dans votre SQL est la plupart du temps correcte, vous venez de l'implémenter mal pour que SQL aime faire des choses. A partir de votre table Dates comme vous l'avez déjà fait, plutôt que de faire un sous-sélection pour chaque ligne de données, changer votre logique à un join et vous êtes là:

select d.DateKey 
     ,count(m.MembershipID) as MembershipCount 
from DIM.[Date] as d 
    left join Memberships as m 
     on(d.DateKey between m.ValidFromDateKey and m.ValidToDateKey) 
where d.CalendarYear = 2016 
group by d.DateKey 
order by d.DateKey; 

Qu'est-ce que vous pouvez Faites attention à identifier les abonnements qui doivent être comptés chaque jour. Par exemple, si votre date est 2006-05-09, est-ce que MembershipID 0001 doit être inclus car il se termine ce jour-là? La question est essentiellement, est-ce que vous comptez le nombre d'Adhésions qui étaient actives au n'importe quel point pendant toute la journée, ou seulement celles qui étaient actives à un moment donné, dites le début ou la fin de la journée?

Ensuite, répétez ce processus de réflexion pour vos valeurs ValidFromDate.

+0

Fantastique! Cela fonctionne parfaitement - Lorsque ma requête a duré> 30 secondes, je l'ai annulée, mais elle fonctionne maintenant toute l'année en <1 seconde. Merci pour le commentaire concernant les dates aussi. J'ai juste besoin de savoir si l'adhésion était valide à n'importe quel point de chaque jour et les dates ValidTo/From sont incluses, ainsi votre question est sur place. – triplestones

+0

Wow! Si cela vous donne la performance dont vous avez besoin, alors c'est un bon moyen d'y aller. Il existe d'autres approches lorsque le non-equijoin prend trop de temps. –

+0

@triplestones SQL fonctionne avec des ensembles de données et est donc très efficace pour assembler des ensembles de données. Les tableaux ne sont que des ensembles de données. Lorsque vous mettez une autre instruction 'select' dans votre' select' principal, elle est exécutée pour chaque ligne qui est retournée, plutôt que juste une fois et 'joined 'ensemble. Pour en savoir plus, cherchez "Set Based Thinking" – iamdave