Oracle
 sql >> Base de données >  >> RDS >> Oracle

Comment gérer au mieux les valeurs de recherche historiques dans une base de données ?

Il existe une technique appelée versioning qui existe depuis de nombreuses années mais qui est en grande partie inapplicable pour plusieurs raisons. Cependant, il existe une technique similaire que j'appelle Version Normal Form et que j'ai trouvée très utile. Voici un exemple utilisant une table Employés.

Tout d'abord, la table statique est créée. Il s'agit de la table d'entité principale et elle contient des données statiques sur l'entité. Les données statiques sont des données qui ne devraient pas changer au cours de la vie de l'entité, telles que la date de naissance.

create table Employees(
  ID        int  auto_generated primary key,
  FirstName varchar( 32 ),
  Hiredate  date not null,
  TermDate  date,            -- last date worked
  Birthdate date,
  ...              -- other static data
);

Il est important de réaliser qu'il y a une entrée pour chaque employé, comme pour n'importe quelle table de ce type.

Puis la table de version associée. Cela établit une relation de 1 m avec la table statique car il peut y avoir plusieurs versions pour un employé.

create table Employee_versions(
  ID         int   not null,
  EffDate    date  not null,
  char( 1 )  IsWorking not null default true,
  LastName   varchar( 32 ),    -- because employees can change last name
  PayRate    currency not null,
  WorkDept   int   references Depts( ID ),
  ...,              -- other changable data
  constraint PK_EmployeeV primary key( ID, EffDate )
);

Dans la note du tableau des versions, il y a une date d'effet mais pas de champ correspondant qui n'est plus en vigueur. En effet, une fois qu'une version prend effet, elle reste en vigueur jusqu'à ce qu'elle soit remplacée par la version suivante. La combinaison ID et EffDate doit être unique afin qu'il ne puisse pas y avoir deux versions pour le même employé qui soient actives en même temps, ni qu'il y ait un intervalle entre le moment où une version se termine et le moment où la prochaine version démarre.

La plupart des requêtes voudront connaître la version actuelle des données sur les employés. Ceci est fourni en joignant la ligne statique de l'employé avec la version en vigueur actuellement. Cela peut être trouvé avec la requête suivante :

select  ...
from    Employees e
join    Employee_versions v1
    on  v1.ID = e.ID
    and v1.EffDate =(
        select  Max( v2.EffDate )
        from    EmployeeVersions v2
        where   v2.ID = v1.ID
            and v2.EffDate <= NOW()
    )
where  e.ID = :EmpID;

Cela renvoie la seule et unique version qui a commencé dans le passé le plus récent. Utilisation de l'inégalité <=dans le contrôle de date (v2.EffDate <= NOW() ) permet des dates d'entrée en vigueur dans le futur. Supposons que vous sachiez qu'un nouvel employé commencera le premier jour du mois prochain ou qu'une augmentation de salaire est prévue pour le 13 du mois prochain, ces données peuvent être insérées à l'avance. Ces entrées "préchargées" seront ignorées.

Ne laissez pas la sous-requête vous atteindre. Tous les champs de recherche sont indexés donc le résultat est assez rapide.

Il y a beaucoup de flexibilité avec cette conception. La requête ci-dessus renvoie les dernières données de tous les employés, présents et passés. Vous pouvez vérifier le TermDate champ pour obtenir seulement les employés présents. En fait, étant donné qu'un bon nombre d'endroits dans vos applications ne seront intéressés que par les informations actuelles des employés actuels, cette requête donnerait une bonne vue (omettez le dernier where clause). Les applications n'ont même pas besoin de savoir que de telles versions existent.

Si vous avez une date particulière et que vous souhaitez voir les données qui étaient en vigueur à ce moment-là, modifiez le v2.EffDate <= NOW() dans la sous-requête à v2.EffDate <= :DateOfInterest .

Plus de détails peuvent être trouvés dans une présentation de diapositives ici et un document pas tout à fait complet ici.

Pour montrer un peu l'extensibilité de la conception, notez qu'il y a un IsWorking indicateur dans la table des versions ainsi qu'une date de fin dans la table statique. Lorsqu'un employé quitte l'entreprise, la dernière date est insérée dans la table statique et une copie de la dernière version avec IsWorking défini sur false est inséré dans la table des versions.

Il est assez courant pour les employés de quitter une entreprise pendant un certain temps, puis d'être embauchés à nouveau. Avec juste la date dans la table statique, l'entrée peut être réactivée simplement en remettant cette date à NULL. Mais une requête "regarder en arrière" pour tout moment où la personne n'était plus un employé renverrait un résultat. Rien n'indiquerait qu'ils aient quitté l'entreprise. Mais une version avec IsWorking =false lors du départ de l'entreprise et IsWorking =vrai lors du retour dans l'entreprise permettra une vérification de cette valeur au moment de l'intérêt et ignorera les employés lorsqu'ils n'étaient plus un employé même s'ils sont revenus plus tard.