2009-09-11 11 views
0

j'ai tout à fait quelques situations où j'ai des structures de base de données similaires à:Stocker les dates dépendantes dans SQL

TABLE Event (INT EventID PrimaryKey, Début DATETIME, Terminer DATETIME); et TABLE EventTask (EventTaskID INT PrimaryKey, EventID INT ForeignKey, TaskStart DATETIME, TaskFinish DATETIME)

1 à plusieurs entre événements et EventTasks, etc.

Lorsque les dates de la table d'événements sont modifiés, le EventTask les dates doivent être changées aussi - pas difficile avec les fonctions de date fournies, mais la manipulation de la date est toujours un peu difficile. Je me demandais s'il ne vaudrait pas mieux remplacer TaskStart DATETIME et TaskFinish DATETIME par deux INTS: un pour Event.Start offset (mins different pour Event.Start) et un Duration.

Cette mise à jour des dates de mise à jour devient beaucoup plus robuste, car une seule ligne nécessite une mise à jour.

(Je stipule que cela ne vaut que lorsque les dates de EventTask sont tout à fait en fonction des dates de l'événement)

Répondre

2

Oui, cela semble tout à fait raisonnable pour moi. Le principal inconvénient serait que, pour trouver les temps réels des EventTasks, vous devez effectuer des calculs. Cela ralentira tout retour des temps, et en particulier nuira aux requêtes impliquant des temps EventTask dans le filtre - par ex. "Trouvez-moi toutes les tâches qui se produisent entre les temps X et Y." Ceux-ci auraient pu auparavant utiliser un index, mais ne le pourront plus.

+0

Bon point pour interroger les temps EventTask Jon. Le design 'original' aurait besoin d'une vue pour le recréer quand même; Je me demande si vous pourriez appliquer un index à cette vue (selon SQLS2008)? – realcals

+0

@realcals: Eventuellement. Je n'ai aucune idée de son efficacité. Les ingénieurs de base de données sont des gens terriblement intelligents parfois :) Quoi qu'il en soit, quelque chose à tester avant d'aller trop loin, je dirais. –

1

Si vous utilisez SQL 2008, vous pouvez utiliser le type de données datetimeoffset. Si vous souhaitez obtenir "directement" les données, sans trop de tracas, vous pouvez utiliser computed columns, mais vous pourriez ne pas être en mesure de créer des index (ou de leur faire stocker le résultat) sur eux si le résultat est non déterministe .

Votre structure serait comme ceci:

TABLE [Event] (
    EventID INT PrimaryKey, 
    Start DATETIME, 
    Finish DATETIME) 

TABLE [EventTask](
    EventTaskID INT PrimaryKey, 
    EventID INT ForeignKey, 
    TaskStart DATETIMEOFFSET, 
    TaskFinish DATETIMEOFFSET, 
    EventTaskStart as [getStartDateByEvent](eventId, TaskStart) <PERSISTED>, 
    EventTaskStop as [getStopDateByEvent](eventId, TaskStart) <PERSISTED>, 
    ) 

FUNCTION [getStartDateByEvent](eventId, TaskStart) as DATETIME 
BEGIN 
    SELECT [EVENT].start + TaskStart from [EVENT] WHERE [EVENT].EVENTID = eventID 
END 

FUNCTION [getStartDateByEvent](eventId, TaskStop) as DATETIME 
BEGIN 
    SELECT [EVENT].[finish] + TaskStop from [EVENT] WHERE [EVENT].EVENTID = eventID 
END 
+0

Je ne vois pas comment cela aide - il ne vous permet pas de spécifier un décalage d'un champ dans une autre table, n'est-ce pas? –

+0

vous devez toujours calculer la valeur. Vous ne pouvez pas utiliser des colonnes calculées qui référencent directement une autre table, mais vous pouvez le faire avec des fonctions définies par l'utilisateur. –

+0

Voici un exemple de colonnes calculées avec le résultat datetime: http://stackoverflow.com/questions/246666/persisting-a- computed-datetime-column-in-sql-server-2005/247092 # 247092 –

0

Jon Skeet:

pour effectuer des calculs. Cela va ralentir quoi que ce soit en retournant le fois, et en particulier fera mal requêtes impliquant des temps EventTask dans le filtre - par exemple. "Trouvez-moi toutes les tâches qui se produisent entre les temps X et Y."

Il me semble que vous avez déjà cette exigence lors de l'écriture des contraintes d'intégrité des données de base, par ex. les dates de tâche d'un événement doivent être comprises dans les dates de l'événement lui-même, par ex. l'expansion de votre schéma dans DLL SQL:

CREATE TABLE Event 
(
EventID INTEGER NOT NULL PRIMARY KEY, 
event_Start DATETIME NOT NULL, 
event_Finish DATETIME NOT NULL, 
CHECK (event_Start < event_Finish), 
UNIQUE (event_Start, event_Finish, EventID) 
) 

CREATE TABLE EventTask 
(
EventTaskID INTEGER NOT NULL PRIMARY KEY, 
EventID INTEGER NOT NULL, 
event_Start DATETIME NOT NULL, 
event_Finish DATETIME NOT NULL, 
FOREIGN KEY (event_Start, event_Finish, EventID) 
    REFERENCES Event (event_Start, event_Finish, EventID) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
event_task_START DATETIME NOT NULL, 
event_task_Finish DATETIME NOT NULL, 
CHECK (event_task_Start < event_task_Finish), 
CHECK (event_Start <= event_task_Start), 
CHECK (event_Finish <= event_task_Finish) 
); 

Si donc les tâches d'un événement sont séquentiels, vous devrez également nous écrire une contrainte pour éviter des périodes qui se chevauchent, ce qui impliquerait une sous-requête (la plupart des produits SQL ne supportent pas cela pour CHECK contrainte, par exemple dans SQL Server, vous devrez recourir à un déclencheur). Si vous deviez recalculer des offsets en utilisant des fonctions temporelles (DATEADD etc), alors les performances pourraient être un problème dans un environnement à haute activité, sans parler de la complexité accrue du code DLL SQL.Pour ces raisons, je modéliserais des périodes en utilisant une paire de données de début et de fin comme suggéré par votre spécification.

Questions connexes