Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Monday, April 18, 2016

How to find next (n) open days from SQL opening Hours Database

How to find next (n) open days from SQL opening Hours Database


I am using a SQL database schema similar to the one found on this link. Best way to store working hours and query it efficiently

I am storing the Opening hours for a location using this basic schema

  • Shop - INTEGER
  • DayOfWeek - INTEGER (0-6)
  • OpenTime - TIME
  • CloseTime - TIME

What i am trying to do however is for the current DateTime (i.e. today) get the NEXT (n) number of days that the shop is open. So for example if i wasnted to find the next three days that the shop was open and configured in the opening hours the shop is closed on a Sunday and todays date is 21/02/2015 (Saturday) I would like to return the days (21/02/2015)Saturday, (23/02/2015)Monday and (23/02/2015)Tuesday.

If it was Sunday i would return (23/02/2015)Monday, (24/02/2015)Tuesday and (25/02/2015)Wednesday (as its closed on sunday) and finally if it was (20/02/2015)Friday it would return (20/02/2015)Friday, (21/02/2015)Saturday, (23/02/2015)Monday.

I dont know if this is easier to do in SQL or C# but i am mentally struggling in if figuring out how to calculate this.

Any pointers, guidance would be great.

Thank you

Answer by Giorgi Nakeuri for How to find next (n) open days from SQL opening Hours Database


Try this:

DECLARE @t TABLE(WeekID INT, OpenTime time)  DECLARE @c INT = 10    INSERT INTO @t VALUES  (1, '10:00'),--sunday  (2, '10:00'),--monday  (4, '10:00'),--wednsday  (5, '10:00')--thursday      ;WITH Tally (n) AS  (      -- 1000 rows      SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))      FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) a(n)      CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(n)      CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(n)  )  SELECT TOP (@c) DATEADD(dd, t.n, GETDATE())  FROM Tally t  JOIN @t s ON DATEPART(w, DATEADD(dd, t.n, GETDATE())) = s.WeekID  

Output:

Date  2015-02-22 --sunday  2015-02-23 --monday  2015-02-25 --wednsday  2015-02-26 --thursday  2015-03-01 --sunday  2015-03-02 --monday  2015-03-04 --wednsday  2015-03-05 --thursday  2015-03-08 --sunday  2015-03-09 --monday  

PS: You can replace GETDATE() with any date to look from.

Answer by Andomar for How to find next (n) open days from SQL opening Hours Database


You can use a case to make a day earlier in this week look like that day next week. Here's an example to look up the next open day:

select  top 1 dateadd(day, day_diff, @dt) as dt  from    (          select  case                   when dayofweek <= datepart(dw, @dt) then dayofweek + 7                  else dayofweek                  end - datepart(dw, @dt) as day_diff          ,       *          from    dbo.OpeningHours          ) sub1  order by          day_diff  

You can then recurse to find more than one day. If we store the above snippet in a function called get_next_open_day, the recursive common table expression could look like:

; with  cte as          (          select  dbo.get_next_open_day(@dt) as open_day          ,       1 as day_number          union all          select  dbo.get_next_open_day(prev_day.open_day)          ,       prev_day.day_number + 1          from    cte as prev_day          where   prev_day.day_number < @number_of_days          )  select  cte.open_day  ,       datename(dw, cte.open_day)  from    cte  option  (maxrecursion 100)  ;  

Here's a full working example:

use Test    if object_id('OpeningHours') is not null      drop table OpeningHours;  if object_id('dbo.get_next_open_day') is not null      drop function dbo.get_next_open_day;    create table OpeningHours (dayofweek int, opentime time, closetime time);  insert dbo.OpeningHours values       (2, '9:00', '17:00'),      (3, '9:00', '17:00'),      (4, '9:00', '17:00'),      (5, '9:00', '17:00'),      (6, '9:00', '21:00'),      (7, '10:00', '17:00')      ;  go  create function dbo.get_next_open_day(      @dt date)       returns date  as begin return      (      select  top 1 dateadd(day, day_diff, @dt) as dt      from    (              select  case                       when dayofweek <= datepart(dw, @dt) then dayofweek + 7                      else dayofweek                      end - datepart(dw, @dt) as day_diff              ,       *              from    dbo.OpeningHours              ) sub1      order by              day_diff      )  end  go    --declare @dt date = '2015-02-18' -- Wed  --declare @dt date = '2015-02-20' -- Fri  declare @dt date = '2015-02-22' -- Sun  declare @number_of_days int = 10    ; with  cte as          (          select  dbo.get_next_open_day(@dt) as open_day          ,       1 as day_number          union all          select  dbo.get_next_open_day(prev_day.open_day)          ,       prev_day.day_number + 1          from    cte as prev_day          where   prev_day.day_number < @number_of_days          )  select  cte.open_day  ,       datename(dw, cte.open_day)  from    cte  option  (maxrecursion 100)  ;  

The implementation of multiple shops is left as an exercise for the reader.

Answer by juharr for How to find next (n) open days from SQL opening Hours Database


First you can use a simple query like the following to get the days of the week that the shop is open

Select DayOfWeek  From OpenHours  Where ShopId = @ShopID  

This assumes that there will not be entries for days that are not open. Adjust this query if instead the open hour column is null, or less than or equal to the close time for days that are not open.

After you run that query and get the results back and preferably translate them into a List you can do the following in your code.

List openDays = GetOpenDaysFromDB();  DateTime start = DateToStartFrom;  int n = numberOfDays;    List nextNOpenDays = new List();    while(nextNOpenDays.Count < n)  {      if(openDays.Contains(start.DayOfWeek))          nextNOpenDays.Add(start);      start = start.AddDays(1);  }  

Answer by Elliveny for How to find next (n) open days from SQL opening Hours Database


This will give you up to 10 days ahead in a fairly efficient way. First test data:

DECLARE @DaysAhead TABLE (      Delta INT    )  INSERT INTO @DaysAhead (Delta)  SELECT 0  UNION ALL SELECT 1  UNION ALL SELECT 2  UNION ALL SELECT 3  UNION ALL SELECT 4  UNION ALL SELECT 5  UNION ALL SELECT 6  UNION ALL SELECT 7  UNION ALL SELECT 8  UNION ALL SELECT 9  UNION ALL SELECT 10    DECLARE @Opening TABLE (      Shop INT,      DayOfWk INT,      DayNm varchar(10),      OpenTime TIME,      CloseTime TIME    )    INSERT INTO @Opening (Shop, DayOfWk, DayNm, OpenTime, CloseTime)  SELECT 1, 5, 'Fri', '09:00', '17:00' --   UNION ALL SELECT 1, 6, 'Sat' ,'09:00', '17:00'  --UNION ALL SELECT 0, 'Sun', '09:00', '17:00' -- Not open on Sunday  UNION ALL SELECT 1, 1, 'Mon', '09:00', '17:00'  UNION ALL SELECT 1, 2, 'Tue', '09:00', '17:00'  UNION ALL SELECT 1, 3, 'Wed', '09:00', '17:00'  

Which can be queried like this:

DECLARE @dt datetime='21-Feb-2015'  DECLARE @dow int=datepart(dw, @dt)-1    SELECT TOP 3 o.Shop, o.DayOfWk, o.DayNm, o.OpenTime, o.CloseTime FROM (    SELECT Delta, ((@dow+Delta)%7) as DayOfWk     FROM @DaysAhead  ) daysAhead  INNER JOIN @Opening o on o.DayOfWk=daysAhead.DayOfWk  ORDER BY daysAhead.Delta  

Results:

DECLARE @dt datetime='20-Feb-2015' -- Fri    1   5   Fri 09:00:00.0000000    17:00:00.0000000  1   6   Sat 09:00:00.0000000    17:00:00.0000000  1   1   Mon 09:00:00.0000000    17:00:00.0000000    DECLARE @dt datetime='21-Feb-2015' -- Sat    1   6   Sat 09:00:00.0000000    17:00:00.0000000  1   1   Mon 09:00:00.0000000    17:00:00.0000000  1   2   Tue 09:00:00.0000000    17:00:00.0000000    DECLARE @dt datetime='22-Feb-2015' -- Sun    1   1   Mon 09:00:00.0000000    17:00:00.0000000  1   2   Tue 09:00:00.0000000    17:00:00.0000000  1   3   Wed 09:00:00.0000000    17:00:00.0000000  

Answer by kalabo for How to find next (n) open days from SQL opening Hours Database


I managed to find a solution:

        public List getDaysOpen(int numberOfDays, DateTime start)      {          List openDays = this.getOpeningHoursDays();          List nextNOpenDays = new List();            while (nextNOpenDays.Count < numberOfDays)          {              if (openDays.Contains(Convert.ToByte(start.DayOfWeek)))                  nextNOpenDays.Add(start);              start = start.AddDays(1);          }          return nextNOpenDays;      }        public List getOpeningHoursDays()      {          return db.OpeningHours.Where(oh => oh.LocationId == this.Id).Select(oh => oh.DateOfWeek).ToList();      }  

This was in my opinion the easiest method to find a solution. Thank you for all your help.


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.