Le tableau sur lequel je travaille comporte trois éléments:
- Une
ID
colonne (clé primaire dans une autre table) - Quelques colonnes de données
- Date valide
from
/to
colonnes.
Valeurs:
ID Data From To
1 a 2015-01-01 2015-01-05
1 a 2015-01-06 2015-01-10
1 b 2015-01-11 2015-01-15
1 a 2015-01-16 2015-01-20
2 c 2015-01-01 2015-01-05
2 c 2015-01-06 2015-01-10
Le tableau est mis à jour en prenant des «instantanés» d'une autre source de données à certains intervalles et en attribuant des dates de validité aux enregistrements. Le problème est que ces instantanés créent des entrées en double pour les enregistrements (avec des dates de validité différentes) qui n'ont pas été modifiées du tout pendant cet intervalle.
Je souhaite réduire la taille du tableau en recherchant des lignes avec des dates consécutives et en les fusionnant et en leur affectant une seule période de validité. Par exemple:
ID Data From To
1 a 2015-01-01 2015-01-10
1 b 2015-01-11 2015-01-15
1 a 2015-01-16 2015-01-20
2 c 2015-01-01 2015-01-10
La logique que j'ai actuellement est la suivante:
- Sélectionnez et triez toutes les lignes par ID, champs de données et champs «valides à partir de» (afin qu'ils soient en groupes de lignes consécutives).
- Utilisez un curseur pour comparer les lignes adjacentes à des fins de similitude.
- S'ils sont identiques, fusionnez les lignes et modifiez la période de validité pour inclure les deux lignes.
Je comprends que les curseurs sont très inefficaces (j'ai un grand ensemble de données), donc je cherche d'autres approches.
CREATE TABLE
énoncé dans la question.Réponses:
S'il s'agit uniquement d'un tableau de plages consécutives, votre cas peut être traité comme un problème classique de "lacunes et d'îlots", où il vous suffit d'isoler des îles de plages consécutives, puis de les "condenser" en prenant le minimum
[from]
et le maximum[to]
par île.Il existe une méthode établie pour résoudre ce problème à l'aide de deux appels ROW_NUMBER:
Cette requête fonctionnera dans une version aussi basse que SQL Server 2005.
la source
J'ai pu écrire une requête pour résoudre ce problème. Il utilise plusieurs jointures et une boucle while pour fusionner les enregistrements. Ce code est compatible avec SQL Server 2008 R2.
la source
Juste pour le cas où vous avez des plages de dates non contiguës qui, même si consécutives, doivent rester séparées, j'ai trouvé cette solution:
Voir sur SQL Fiddle
la source
J'ai écrit une requête qui semble fonctionner. Il utilise des expressions de table communes, des instructions MERGE et des fonctions analytiques. Cependant, il n'est compatible qu'avec SQL Server 2012+. Vous pouvez trouver l'essentiel ici: MergeRecordsByValidityDate.sql
la source