2009-12-14 12 views
5

Ho una tabella che comprende, tra le altre cose, due campi denominati StartTime e EndTime. Entrambi sono campi TIME.Campi intervallo di date univoci in SQL Server 2008

Desidero aggiungere un vincolo che impedisca l'inserimento di qualsiasi record che si sovrapponga a intervalli di tempo preesistenti. Per esempio. se un record esiste già con StartTime = 5:00, EndTime = 10:00, vorrei un inserto con StartTime = 6:00, EndTime = 9:00 per fallire a causa della sovrapposizione.

C'è un modo per farlo, con o senza trigger?

risposta

4

Il limite al di sotto dovrebbe funzionare - è anche possibile fare questo con vincoli di controllo, ma la logica mostrata nella this post genere mi fa male la testa

CREATE TRIGGER [dbo].[DateRangeTrigger] 
    ON [dbo].[TargetTable] 
    FOR INSERT, UPDATE 
AS 
BEGIN 

IF EXISTS (SELECT t.starttime, t.endtime FROM TargetTable t 
     Join inserted i 
     On (i.starttime > t.starttime AND i.starttime < t.endtime AND i.UniqueId <> t.UniqueId) 
      OR (i.endtime < t.endtime AND i.endtime > t.starttime AND i.UniqueId <> t.UniqueId) 
      OR (i.starttime < t.starttime AND i.endtime > t.endtime AND i.UniqueId <> t.UniqueId) 
     ) 
BEGIN 
    RAISERROR ('Inserted date was within invalid range', 16, 1) 
    IF (@@TRANCOUNT>0) 
     ROLLBACK 
END 


END 
+0

Perfetto, grazie David! Funziona esattamente come volevo. –

+0

Whoops, un'altra domanda. Non funzionerà solo per l'inserimento? Si acquisisce l'aggiornamento anche nel trigger, ma vedo solo un inserimento di gestione del caso. –

+0

Hmmmm - guardando a questo, non penso che il caso di aggiornamento sia possibile senza includere qualche chiave primaria da sfruttare. Ho aggiornato la mia risposta. –

4

Non ho provato, ma immagino che qualcosa di simile potrebbe funzionare:

create trigger preventOverlaps 
on infotable 
FOR Insert, Update 
As 
DECLARE @Count int; 
select @Count = count(*) from infotable where 
    (inserted.startdate > startDate && inserted.startdate < endDate) || 
    (inserted.endDate < endDate && inserted.endDate > startDate) 
if(@Count > 0) 
begin 
    rollback transaction; 
end 
+0

Sarebbe questo lavoro in SQL Server? – gbn

+0

+1 da parte mia - in qualche modo quando ho provato per la prima volta questo FOR non sembra funzionare correttamente. Più tardi, controllandolo, ha funzionato bene. Sto lasciando la mia risposta solo per avere la sintassi t-sql su && e ||. –

+0

Ti manca il caso in cui un intervallo temporale comprende completamente l'altro - come la risposta di David Hall mostra che hai bisogno di un ulteriore controllo nella tua logica. – riskyc123

0

Questo trigger funziona anche in situazioni in cui un intervallo di tempo contiene completamente l'altro. Ad esempio, se c'è un record esistente per 6:00 - 9:00 e si tenta di inserirlo uno per 5:00 - 10:00.
(Basato su risposta di David Hall)

CREATE TRIGGER DateRangeOverlapTrigger 
ON TargetTable 
FOR INSERT, UPDATE 
AS 
BEGIN 
IF EXISTS 
    (SELECT t.UniqueId 
    FROM TargetTable t 
     JOIN inserted i ON i.starttime < t.endtime 
      AND i.endtime > t.starttime 
      AND i.UniqueId <> t.UniqueId) 
BEGIN 
    RAISERROR ('Invalid due to time overlap', 16, 1) 
    IF (@@TRANCOUNT > 0) 
     ROLLBACK 
END 
END 
+0

Questo trigger funziona solo per le istanze che si contengono SOLO l'una con l'altra, non una sovrapposizione parziale. È necessaria una combinazione delle due risposte. –

+0

@bytenik: Non riesco a vedere quale sia il problema. Puoi dare un esempio specifico per il quale il trigger non funzionerà? – Whatsit

Problemi correlati