Compte tenu des données suivantes:
create table #histories
(
username varchar(10),
account varchar(10),
assigned date
);
insert into #histories
values
('PHIL','ACCOUNT1','2017-01-04'),
('PETER','ACCOUNT1','2017-01-15'),
('DAVE','ACCOUNT1','2017-03-04'),
('ANDY','ACCOUNT1','2017-05-06'),
('DAVE','ACCOUNT1','2017-05-07'),
('FRED','ACCOUNT1','2017-05-08'),
('JAMES','ACCOUNT1','2017-08-05'),
('DAVE','ACCOUNT2','2017-01-02'),
('PHIL','ACCOUNT2','2017-01-18'),
('JOSH','ACCOUNT2','2017-04-08'),
('JAMES','ACCOUNT2','2017-04-09'),
('DAVE','ACCOUNT2','2017-05-06'),
('PHIL','ACCOUNT2','2017-05-07') ;
... qui indique quand un utilisateur donné a été affecté à un compte.
Je cherche à déterminer à qui appartient un compte donné le dernier jour de chaque mois (la date attribuée est la date à laquelle le compte a transféré la propriété), avec les fins de mois manquantes renseignées (éventuellement créées à partir d'un dates
tableau pratique dont je dispose, avec des colonnes utiles DateKey
, Date
et LastDayOfMonth
, [avec l'aimable autorisation de @AaronBertrand]) 1 .
Les résultats souhaités seraient:
PETER, ACCOUNT1, 2017-01-31
PETER, ACCOUNT1, 2017-02-28
DAVE, ACCOUNT1, 2017-03-31
DAVE, ACCOUNT1, 2017-04-30
FRED, ACCOUNT1, 2017-05-31
FRED, ACCOUNT1, 2017-06-30
FRED, ACCOUNT1, 2017-07-31
JAMES, ACCOUNT1, 2017-08-31
PHIL, ACCOUNT2, 2017-01-31
PHIL, ACCOUNT2, 2017-02-28
PHIL, ACCOUNT2, 2017-03-31
JAMES, ACCOUNT2, 2017-04-30
PHIL, ACCOUNT2, 2017-05-31
Faire la première partie de cela avec une fonction de fenêtrage est trivial, c'est ajouter les lignes "manquantes" avec lesquelles je me bats.
2017-05
parce qu'il l'avait2017-05-07
et qu'il n'y avait pas de titulaire subséquent?Réponses:
Une approche à ce problème consiste à procéder comme suit:
LEAD
sur SQL Server 2008. Vous pouvez utiliserAPPLY
ou une sous-requête pour cela.J'ai un peu modifié vos données de test pour rendre les résultats déterministes. Ajout d'un index:
Voici le tableau des dimensions de date le plus paresseux de tous les temps:
Pour l'étape 1, il existe de nombreuses façons d'émuler
LEAD
. Voici une méthode:Pour l'étape 2, nous devons remplacer les valeurs NULL par autre chose. Vous souhaitez inclure le dernier mois de chaque compte, il suffit donc d'ajouter un mois à la date de début:
Pour l'étape 3, nous pouvons rejoindre le tableau des dimensions de date. La colonne du tableau des dimensions est exactement la colonne dont vous avez besoin pour le jeu de résultats:
Je n'ai pas aimé la requête que j'ai reçue quand j'ai tout rassemblé. Il peut y avoir des problèmes avec l'ordre de jointure lors de la combinaison de
OUTER APPLY
etINNER JOIN
. Pour obtenir l'ordre de jointure que je voulais, je l'ai réécrit avec une sous-requête:Je ne sais pas combien de données vous avez, donc cela pourrait ne pas avoir d'importance pour vous. Mais le plan ressemble à ce que je veux:
Les résultats correspondent aux vôtres:
la source
Ici, je n'utilise pas de table de calendrier, mais une table de nombres naturels nums.dbo.nums (j'espère que vous l'avez aussi, sinon, elle peut être facilement générée)
J'ai la réponse légèrement différente de la vôtre ('JOSH' <-> 'JAMES') car vos données contiennent ces 2 lignes:
avec le même compte et la même date et vous n'avez pas précisé lequel choisir, c'est cette situation.
la source
Ce n'est en aucun cas une solution propre, mais elle semble fournir les résultats que vous recherchez (je suis sûr que d'autres auront des requêtes agréables, propres et entièrement optimisées pour vous).
la source
J'ai utilisé la table de dimension de date d'Aaron Bertrand, comme vous le mentionnez également dans votre question (qui est une table très pratique pour de tels scénarios) et j'ai écrit le code suivant:
J'ai ajouté la
EndOfMonth
colonne au#dim
tableau (juste après laFirstOfMonth
colonne) en utilisant le code suivant:Et la solution:
la source
Triangle REJOIGNEZ pour la victoire!
Les résultats sont:
Plan d'exécution interactif ici.
Statistiques d'E / S et de TEMPS (tronqué toutes les valeurs nulles après les lectures logiques):
Recherchez les tables temporaires requises et testez l'instruction T-SQL que je suggère:
la source