Oracle
 sql >> Database >  >> RDS >> Oracle

Come gestire al meglio i valori di ricerca cronologica in un database?

Esiste una tecnica chiamata versioning che esiste da molti anni ma è in gran parte impraticabile per diversi motivi. Tuttavia, esiste una tecnica simile che chiamo Version Normal Form che ho trovato molto utile. Ecco un esempio di utilizzo di una tabella Dipendenti.

Innanzitutto, viene creata la tabella statica. Questa è la tabella dell'entità principale e contiene dati statici sull'entità. I dati statici sono dati che non dovrebbero cambiare durante la vita dell'entità, come la data di nascita.

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
);

È importante rendersi conto che esiste una voce per ogni dipendente, proprio come con qualsiasi tabella di questo tipo.

Quindi la tabella delle versioni associata. Questo stabilisce una relazione di 1 m con la tabella statica poiché potrebbero esserci diverse versioni per un dipendente.

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 )
);

Nella nota della tabella delle versioni è presente una data di validità ma non un campo corrispondente non più valido. Questo perché una volta che una versione diventa effettiva, rimane in vigore fino a quando non viene sostituita dalla versione successiva. La combinazione di ID ed EffDate deve essere univoca, quindi non possono esserci due versioni per lo stesso dipendente attive contemporaneamente, né può esserci un intervallo tra il momento in cui una versione termina e l'inizio della versione successiva.

La maggior parte delle query vorrà conoscere la versione corrente dei dati dei dipendenti. Ciò viene fornito unendo la riga statica per il dipendente con la versione attualmente in vigore. Questo può essere trovato con la seguente query:

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;

Questo restituisce l'unica versione iniziata nel passato più recente. Usando la disuguaglianza <=nel controllo della data (v2.EffDate <= NOW() ) consente date di entrata in vigore in futuro. Supponiamo che tu sappia che un nuovo dipendente inizierà il primo giorno del mese successivo o che un aumento della retribuzione sia previsto per il 13 del mese successivo, questi dati possono essere inseriti in anticipo. Tali voci "precaricate" verranno ignorate.

Non lasciare che la sottoquery ti raggiunga. Tutti i campi di ricerca sono indicizzati, quindi il risultato è abbastanza veloce.

C'è molta flessibilità con questo design. La query sopra restituisce i dati più recenti di tutti i dipendenti, presenti e passati. Puoi controllare TermDate campo per ottenere solo dipendenti presenti. In effetti, poiché un buon numero di posti nelle tue app saranno interessati solo alle informazioni attuali dei dipendenti attuali, quella query sarebbe una buona visualizzazione (ometti il ​​where finale clausola). Non c'è bisogno che le app sappiano che esistono versioni di questo tipo.

Se hai una data particolare e vuoi vedere i dati che erano in vigore in quel momento, cambia il v2.EffDate <= NOW() nella sottoquery a v2.EffDate <= :DateOfInterest .

Maggiori dettagli possono essere trovati in una presentazione di diapositive qui e in un documento non del tutto completato qui.

Per mostrare un po' dell'estendibilità del design, nota che c'è un IsWorking indicatore nella tabella delle versioni e una data di fine nella tabella statica. Quando un dipendente lascia l'azienda, nella tabella statica viene inserita l'ultima data e una copia dell'ultima versione con IsWorking impostato su false viene inserito nella tabella delle versioni.

È abbastanza comune che i dipendenti lascino un'azienda per un po' e poi vengano assunti di nuovo. Con solo la data nella tabella statica, la voce può essere riattivata semplicemente riportando quella data a NULL. Ma una query "guarda indietro" per qualsiasi momento in cui la persona non era più un dipendente restituirebbe un risultato. Non ci sarebbe stata alcuna indicazione che avessero lasciato l'azienda. Ma una versione con IsWorking =false quando si lascia l'azienda e IsWorking =true al rientro in azienda consentirà una verifica di tale valore al momento dell'interesse e ignorerà i dipendenti quando non erano più dipendenti anche se rientrati successivamente.