Как найти следующие (n) дни открытых дверей из базы данных SQL

Я использую схему базы данных SQL, аналогичную той, которая найдена в этой ссылке. Лучший способ хранить рабочее время и эффективно его обрабатывать

Я храню часы работы для местоположения, используя эту основную схему

  • Магазин – INTEGER
  • DayOfWeek – INTEGER (0-6)
  • OpenTime – TIME
  • CloseTime – TIME

Однако я пытаюсь сделать это для текущего DateTime (т.е. сегодня) получить NEXT (n) количество дней, когда магазин открыт. Так, например, если я хотел найти следующие три дня, когда магазин был открыт и настроен в часы работы, магазин закрыт в воскресенье, а сегодняшняя дата – 21/02/2015 ( суббота ). Я хотел бы вернуть дни ( 21/02/2015) Суббота, (23/02/2015) понедельник и (23/02/2015) вторник .

Если бы было воскресенье, я вернусь (23/02/2015) понедельник, (24/02/2015) вторник и (25/02/2015) среда (как закрыта в воскресенье) и, наконец, если бы это было (20/02 / 2015) В пятницу он вернется (20/02/2015) Пятница, (21/02/2015) Суббота, (23/02/2015) понедельник .

Я не знаю, легче ли это делать в SQL или C #, но я мысленно боюсь, если выясню, как вычислить это.

Любые указатели, руководство было бы здорово.

спасибо

Это даст вам до 10 дней вперед довольно эффективным способом. Первые тестовые данные:

 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' 

Который может быть запрошен следующим образом:

 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 

Результаты:

 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 

Сначала вы можете использовать простой запрос следующего типа, чтобы получить дни недели, когда магазин открыт

 Select DayOfWeek From OpenHours Where ShopId = @ShopID 

Это предполагает, что в течение дней, которые не открыты, не будет записей. Откорректируйте этот запрос, если вместо этого столбец открытого часа равен нулю или меньше или равен времени закрытия для дней, которые не открыты.

После запуска этого запроса и возврата результатов и, желательно, перевода их в List<DayOfWeek> вы можете сделать следующее в своем коде.

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

Вы можете использовать case чтобы сделать день раньше на этой неделе похожим на этот день на следующей неделе. Вот пример, чтобы посмотреть следующий открытый день:

 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 

Затем вы можете вернуться к более чем одному дню. Если мы сохраним вышеприведенный фрагмент в функции, называемой get_next_open_day , рекурсивное общее табличное выражение может выглядеть так:

 ; 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) ; 

Вот полный рабочий пример:

 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) ; 

Реализация нескольких магазинов остается в качестве упражнения для читателя.

Попробуй это:

 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, tn, GETDATE()) FROM Tally t JOIN @ts ON DATEPART(w, DATEADD(dd, tn, GETDATE())) = s.WeekID 

Вывод:

 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: Вы можете заменить GETDATE() на любую дату, чтобы посмотреть.

Мне удалось найти решение:

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

Это, на мой взгляд, самый простой способ найти решение. Спасибо за твою помощь.

  • Группировка и подсчет SQL на основе дат
  • Учитывая номер недели, верните первый день недели в T-SQL
  • дата даты и даты даты и времени
  • JOIN в строке, по которой строка в запросе соединения имеет значение MAX / MIN всех строк
  • SQL: Возможно ли использовать поля SUM () типа INTERVAL?
  • SQL - дата группы по годам, месяцам, дням
  • SQL Как заказать каждую запись по дате
  • MS SQL сравнить даты?
  • Укажите дату результата, когда они равны
  • SQL конвертирует количество дней в недели
  • Между двумя условиями даты на сервере Sql
  • Interesting Posts

    В SQL Server 2014 в олтепе памяти не хватает памяти

    Как найти разницу между двумя датами в одном столбце?

    Самый надежный способ получить последний идентификатор записи из таблицы

    Не удалось найти решение или обходное решение

    сравнить ячейки и возвращаемые значения в SAS

    хранимая процедура для арабских букв

    У MySQL нет поддержки транзакций?

    Каков правильный способ объединения трех таблиц с использованием EF

    SQL Server: анализ двух значений из одного varchar с переменной длиной

    Динамические результаты SQL в таблице temp в SQL Сохраненная процедура

    Если мой C # истекает с вызовом хранимой процедуры, процедура продолжает работать?

    Есть ли проблема с производительностью с использованием Row_Number для реализации подкачки таблиц в Sql Server 2008?

    Несколько соединений LINQ с одним левым соединением

    Почему Dapper не может вернуть несколько вставленных идентификаторов строк?

    Как найти максимальное значение в таблице

    Давайте будем гением компьютера.