2009-12-14 15 views
5

Tengo una tabla que consiste, entre otras cosas, en dos campos denominados StartTime y EndTime. Ambos son campos TIME.Campos únicos de intervalo de fechas en SQL Server 2008

Quiero agregar una restricción que impida la inserción de cualquier registro que se superponga con intervalos de tiempo preexistentes. P.ej. si ya existe un registro con StartTime = 5:00, EndTime = 10:00, me gustaría una inserción con StartTime = 6:00, EndTime = 9:00 para fallar debido a la superposición.

¿Hay alguna manera de lograr esto, con o sin disparadores?

Respuesta

4

El disparador a continuación debe trabajar - que también es posible hacer esto con contraints de verificación, pero la lógica se muestra en this post especie de lastima mi cabeza

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

Perfecto, gracias David! Esto funciona exactamente como yo quería. –

+0

Whoops, una pregunta más. ¿Esto no funciona solo para insertar? Capturas la actualización también en el desencadenador, pero solo veo una inserción de manejo de casos. –

+0

Hmmmm - mirando esto, no creo que el caso de actualización sea posible sin incluir alguna clave principal para aprovechar. He actualizado mi respuesta con eso. –

4

no lo han intentado, pero me imagino algo como esto funcionaría:

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

Que este trabajo en SQL Server? – gbn

+0

+1 de mí - de alguna manera, cuando probé por primera vez, el FOR no parecía funcionar correctamente. Más tarde, al verificar eso, funcionó bien. Dejo mi respuesta solo para tener la sintaxis t-sql en el && y ||. –

+0

Se pierde el caso en que un intervalo de tiempo abarca completamente al otro, ya que la respuesta de David Hall muestra que necesita una verificación adicional en su lógica. – riskyc123

0

Este disparador también funciona para situaciones en las que un intervalo de tiempo contiene completamente el otro. Por ejemplo, si hay un registro existente para las 6:00 - 9:00 e intenta insertar uno para las 5:00 - 10:00.
(Basado en la respuesta de 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

Este disparador solo funciona para instancias que SOLAMENTE contienen una a la otra, no una superposición parcial. Se necesita alguna combinación de las dos respuestas. –

+0

@bytenik: No puedo ver cuál es el problema. ¿Puedes dar un ejemplo específico de que el gatillo no funcionará? – Whatsit