2009-11-05 4 views
2

Quelle serait la meilleure façon de trouver des dates qui n'avez pas des événements dans un intervalle de temps donné, étant donné que différents événements peuvent se chevaucher, répartis sur plusieurs jours, avant le début de l'intervalle, et fin après l'intervalle.Linq2SQL ou SQL: trouver des dates qui ne sont pas des événements

-à-dire:

event start  end 
e1  01/01/2009 02/01/2009 
e2  01/15/2009 01/31/2009 
e3  08/15/2008 01/16/2009 
e4  02/03/2009 02/15/2009 

avec ces données, nous pouvons voir qu'il n'y a aucun événement sur 2/2/2009.

Répondre

1

Bien que cela ne limite pas par un intervalle de temps, cela vous donnera toutes les lacunes disponibles dans les vos événements:

declare @temp table (evt varchar(10), start datetime, [end] datetime) 

insert into @temp values('e1', '1/1/2009', '2/1/2009') 
insert into @temp values('e2', '1/15/2009', '1/31/2009') 
insert into @temp values('e3', '8/15/2008', '1/16/2009') 
insert into @temp values('e4', '2/3/2009', '2/15/2009'); 

with NextEvent as (select 
    t.evt, 
    tafter.evt nextEvt, 
    tafter.start start, 
    tafter.[end] [end], 
    ROW_NUMBER() over (order by t.evt, tafter.start) - RANK() over (order by t.evt) as number 

from @temp t 

left join @temp tafter on tafter.[end] >= t.[end] and tafter.evt <> t.evt) 

select 
    t.evt, 
    t.start, 
    t.[end], 
    ne.nextEvt [next], 
    ne.start, 
    ne.[end] 

from @temp t 

left join NextEvent ne on ne.evt = t.evt and ne.number = 0 

where ne.start > t.[end] 
+0

Je pense que cela fonctionnerait. –

+0

+1 pour le déclar @temp - Je n'aurais jamais pensé à cela pour une réponse SO ... –

0

Je ne suis pas sûr que je comprends votre question. Pour une date donnée, vous voulez voir le nombre de lignes (événements) retournées?

Donc, pour le 01/02/09, vous devriez voir 1, pour le 02/02/09, vous devriez voir 0 ??? SQL:

declare @temp table (evt varchar(10), start datetime, [end] datetime) 

insert into @temp values('e1', '1/1/2009', '2/1/2009') 
insert into @temp values('e2', '1/15/2009', '1/31/2009') 
insert into @temp values('e3', '8/15/2008', '1/16/2009') 
insert into @temp values('e4', '2/3/2009', '2/15/2009'); 


select * from @temp where start < '2/1/2009' and [end] >= '2/1/2009' 
select * from @temp where start < '2/2/2009' and [end] >= '2/2/2009' 

C#/LINQ:

public class Event 
     { 
      public string eventID; 
      public DateTime start; 
      public DateTime end; 
     } 

     static void Main(string[] args) 
     { 
      IList<Event> events = new List<Event>(); 
      events.Add(new Event { eventID = "e1", start = new DateTime(2009, 1, 1), end = new DateTime(2009, 2, 1) }); 
      events.Add(new Event { eventID = "e2", start = new DateTime(2009, 1, 15), end = new DateTime(2009, 1, 31) }); 
      events.Add(new Event { eventID = "e3", start = new DateTime(2008, 8, 15), end = new DateTime(2009, 1, 16) }); 
      events.Add(new Event { eventID = "e4", start = new DateTime(2009, 2, 3), end = new DateTime(2009, 2, 15) }); 

      DateTime eventDate = new DateTime(2009, 2, 1); 
      var available = events.Where(e => e.start.CompareTo(eventDate) < 1 && e.end.CompareTo(eventDate) > -1); 
      Console.WriteLine(available.Count()); 

      eventDate = new DateTime(2009, 2, 2); 
      available = events.Where(e => e.start.CompareTo(eventDate) < 1 && e.end.CompareTo(eventDate) > -1); 
      Console.WriteLine(available.Count()); 

      eventDate = new DateTime(2009, 1, 16); 
      available = events.Where(e => e.start.CompareTo(eventDate) < 1 && e.end.CompareTo(eventDate) > -1); 
      Console.WriteLine(available.Count()); 
      Console.ReadLine(); 
     } 

EDIT: Ce n'est pas assez, mais ce SQL vous donnera le résultat que vous avez demandé:

declare @temp table (evt varchar(10), start datetime, [end] datetime) 
declare @result table (available datetime) 

insert into @temp values('e1', '1/1/2009', '2/1/2009') 
insert into @temp values('e2', '1/15/2009', '1/31/2009') 
insert into @temp values('e3', '8/15/2008', '1/16/2009') 
insert into @temp values('e4', '2/3/2009', '2/15/2009'); 

declare @start datetime 
declare @end datetime 
set @start = '1/1/2009' 
set @end = '2/16/2009' 

while @start < dateadd(day, 1, @end) 
begin 
    declare @rowCount int 
    select @rowCount = count(*) from @temp where start <= @start and [end] >= @start 
    if @rowCount = 0 
     insert into @result values(@start) 

    set @start = dateadd(day, 1, @start) 
end 
select * from @result 
+0

étant donné une plage de dates, à savoir: startDate 1/1/2009 et endDate 16/02/2009 trouver toutes les dates qui ont aucun événement prévu 2/2/2009 et 2/16/2009 doivent être renvoyés. –

0

Cette Le type de requête est facile si vous utilisez une table de type date ou calendrier. Ce sont des tables d'utilitaires qui sont utilisées pour que vous ayez une table pré-remplie avec des champs qui seraient fastidieux à caluler dans les requêtes (par exemple, IsWeekDay, IsHoliday, FiscalMonth). Ci-dessous, j'ai utilisé une table de calendrier très simple. La requête pour obtenir les dates sans événements finit par être très simple.

Ceci a été créé sur SQL Server 2005

-- Create the #Calendar table 
Create table #Calendar (CalendarDate datetime) 
Set nocount on 
Declare @Date smalldatetime 
Set @Date = '1/1/2000' 
While @Date < '1/1/2015' 
Begin 
    Insert #Calendar select @Date 
    Set @Date = dateadd(dd, 1, @Date) 
End 

-- Create the #Event table 
Create Table #Event (EventName varchar(10), StartDate datetime, EndDate datetime) 

Insert Into #Event 
Select 'e1', '1/1/2009', '2/1/2009' 
Union Select 'e2', '1/15/2009', '1/31/2009' 
Union Select 'e3', '8/15/2008', '1/16/2009' 
Union Select 'e4', '2/3/2009', '2/15/2009' 

-- Return all the dates that do not have events 
Select #Calendar.CalendarDate 
From #Calendar 
Left Join #Event 
    on #Calendar.CalendarDate between #Event.StartDate and #Event.EndDate 
Where 
    #Event.StartDate is null 
    and CalendarDate between 
     (Select min(StartDate) from #Event) 
     and 
     (Select max(EndDate) from #Event) 
Questions connexes