2016-09-15 2 views
1

У меня есть таблица встреч с записями, имеющими два поля: start_date и end_date, как datetime. В таблице нет перекрытия периодов времени.Найти доступные открытия с помощью SQL

Учитывая определенный период (search_start и search_end), мне нужно сгенерировать список всех открытий между этими встречами (от и до) с использованием SQL.

Например: с учетом двух назначений в таблице:

15 сентября 2016 с 08:00 до 15 сентября, 2016 9:00

15 сентября 2016 10:00 до 15 сентября 2016 года 12 : 00

и заданные параметры поиска начать = 1 сентября 2016 00:00 и конец = 30 сентября 2016 23:59, результаты должны быть

1 сентября 2016 00:00 15 сентября 2016 08:00

15 сентября 2016 9:00 15 сентября 2016 10:00

15 сентября 2016 12:00 30 сентября 2016 23:59

Вот скрипт для создания таблицы выборки:

CREATE TABLE [dbo].[Table_1]( 
[from_date] [datetime] NOT NULL, 
[to_date] [datetime] NULL, 
CONSTRAINT [PK_Table_1] PRIMARY KEY CLUSTERED ([from_date] ASC) 
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
    ) ON [PRIMARY] 

    GO 

INSERT [dbo].[Table_1] ([from_date], [to_date]) VALUES (CAST(0x0000A6820083D600 AS DateTime), CAST(0x0000A682009450C0 AS DateTime)) 

INSERT [dbo].[Table_1] ([from_date], [to_date]) VALUES (CAST(0x0000A68200A4CB80 AS DateTime), CAST(0x0000A68200C5C100 AS DateTime)) 

Я использую MSSQL 2008 R2

+1

Вот отличное место для начала. http://spaghettidba.com/2015/04/24/how-to-post-a-t-sql-question-on-a-public-forum/ Учитывая то, что вы опубликовали, нет никаких шансов, мы сможем помочь. –

+0

Какая версия SQL? – SqlOnly

+0

Вы просто хотите отобразить весь результат между двумя датами? – mfredy

ответ

1

Используя ваши значения, я получил вывод, который вы хотели:)

DECLARE @start datetime = '2016-09-01 00:00:00' 
DECLARE @finish datetime = '2016-09-30 23:59:00' 

WITH rn AS (SELECT *, ROW_NUMBER() OVER (ORDER BY start) AS rn FROM opening) 
SELECT CASE WHEN r1.rn = 1 THEN @start 
          ELSE r2.finish 
     END as START, 
     CASE WHEN r1.rn IS NULL THEN @finish 
           ELSE r1.start 
     END AS FINISH 
    FROM rn r1 
     FULL OUTER JOIN rn r2 
      ON r1.rn = r2.rn + 1 
    WHERE ISNULL(r1.start, 0) != @start 

opening ваше расписание/назначение таблицы. start - это дата начала вашей таблицы, а finish - это дата окончания в вашей таблице. @start - дата начала и @finish - дата окончания. Вам явно не нужно использовать @start, @finish. Я просто положил его на тестирование.

+1

Это отлично работает! Мне просто интересно, есть ли более эффективный с точки зрения затрат способ сделать это с точки зрения производительности. См., Например, примеры 3 и 4 на странице http://blog.sqlauthority.com/2013/09/25/sql-server-how-to-access-the-previous-row-and-next-row-value-in- select-statement-part-4/по сравнению с примером 2, но я не мог получить 3 и 4 для работы с моим делом. – user1480192

+0

@ user1480192 Я уверен, что есть способ. Вы не забыли проверить все остальные запросы? Существует несколько способов сделать одну задачу, чтобы кто-то мог найти более эффективный способ. Мой очень прямолинейный. Я посмотрю, посмотрю, смогу ли я сделать это лучше. – CodyMR

+0

@ user1480192 Знаете ли вы, сколько времени потребовалось вам для обработки информации с помощью моего запроса? – CodyMR

0
SELECT Start_Date, End_Date 
FROM TableName 
BETWEEN Start_Date AND End_Date 

Этот вопрос кажется легко ?? Я не уверен, если я упростил ваш вопрос?

Вам просто нужно убедиться, что вы также добавили бит времени!

+0

Это не сработает. Он, по сути, хочет, чтобы между двумя введенными пользователем значениями даты и времени ('start and end') не было времени, которое не существует в его таблице. Подумайте об этом с точки зрения 'int'. В его таблице он «начинает 4, конец 6» и «начинает 9, конец 10». Если его пользователь вводил 'start, end'' '0, 10', то он хочет' 0, 4 - 6, 9'. – CodyMR

0

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

Вот некоторые распространенные проблемы.
Некоторые (как Mysql) SQL-серверы хранят данные в GMT (некоторый часовой пояс в Англии). Затем они подсчитывают количество часов от GMT, чтобы получить фактическое время. Так что, если вам 8 часов с GMT, вы можете отключить 8 часов, если вы используете клиент MsSql, подключающийся к базе данных MySql. Потому что MsSql не понимает эту 8-часовую дельту для GMT, используемую MySql. Вы также можете увидеть это в приложениях и операционных системах.

Другой вопрос: вы думаете, что в датах вы должны убедиться, что думаете о дате и времени, если вы не изменили дату и дату.

Остерегайтесь < против < =. Если вы фильтруете дату окончания. Скажем, например, последний день в январе должен быть включен, но первый день февраля - нет. Лучше сделать < 02/01, что он должен сделать < = 1/31. Вы можете отбивать записи, если сравнивать с < = и не доходить до последней миллисекунды до 02/01.

0

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

Я уверен, что есть еще более элегантные способы, но это отправная точка, и мне очень понравилось выяснять это.

Подход, который я хотел взять было построить список доступных «временных интервалов»

Во-первых, я создал таблицу с имеющимися Часы для заказа

CREATE TABLE [dbo].[HOURS](
HourID [int] NULL) 

INSERT INTO dbo.[hours] VALUES (9),(10),(11),(12),(13),(14),(15),(16),(17) 

Затем сделал то же самое для минутные интервалы (я пошел с 5-минутными интервалами для простоты)

CREATE TABLE [dbo].MINS(
MinID [int] NULL ) 

INSERT INTO dbo.mins VALUES (5),(10),(15),(20),(25),(30),(35),(40),(45),(50),(55),(60) 

и снова же для дат я хотел работать с

CREATE TABLE [dbo].DATES(
DATES [Date] NULL) 

INSERT INTO dbo.DATES values 
('20160901'),('20160902') 

Используя эти таблицы, я создал представление со списком всех доступных «слотов»

CREATE VIEW AllTimeSlots AS 
SELECT 
cast(dates AS datetime) + cast(DATEADD(hour, hourid, DATEADD(minute, minid, DATEADD(second, 00, 0))) AS datetime) AS TimeSlot 
FROM dbo.[hours] CROSS JOIN dbo.mins CROSS JOIN dates 

Затем я создал таблицу, содержащую назначения

CREATE TABLE [dbo].Appointments(
AppointmentStart [Datetime] NULL, 
AppointmentEnd [DateTime] null 
) 

INSERT INTO dbo.Appointments 
VALUES 
('20160901 10:40:00 AM','20160901 10:55 AM'),('20160901 01:00:00 PM','20160901 02:05:00 PM') 

Затем я создал еще один вид с женатыми слоты и заказы. Обратите внимание на стыки я использую, чтобы блокировать все щели между двумя временами

CREATE VIEW SlotAvailability 
AS 
SELECT TimeSlot,CASE WHEN AppointmentStart IS NULL THEN 'Free' ELSE 'Booked' END AS [Availability] 
FROM (
SELECT Timeslot,apt.AppointmentStart, apt.AppointmentEnd FROM 
dbo.AllTimeSlots ats 
LEFT OUTER JOIN dbo.Appointments apt 
on ats.TimeSlot >= appointmentstart and ats.timeslot <= appointmentend) q1 

Ведение

Select Timeslot, [availability] from SlotAvailability where [availability] = 'free' 

будут перечислены все доступные временные интервалы.

Последний бит, к которому у меня еще не добрался (и на этот раз не хватило времени), превращает это в начальное время для каждого «свободного» слота - попробовал несколько методов, но didn 't взломать его - я думаю, что если вы присоединитесь к этой таблице (просмотрите) к себе временному интервалу + 5 минут, вы сможете иметь значения min/max в зависимости от того, является ли это началом/концом свободного блока

0

Путь Обычно я рекомендую сегодня использовать оператор APPLY для присоединения к таблице. Там не достаточно информации в этом вопросе, чтобы ремесленных полный запрос для вас, но вот общая картина:

SELECT * 
FROM MyTable t1 
OUTER APPLY ( 
    SELECT TOP 1 * 
    FROM MyTable t 
    WHERE t.KeyFields = t1.KeyFields 
     AND t.SequenceField > t1.SequenceField 
) t2 

Теперь я могу сопоставить каждую строку непосредственно с того, который следует в моем ИНЕКЕ, так что ИНЕКЕ фильтр вниз, чтобы показывать только строки, где есть пробел.

Вы также можете выполнить это через LAG или LEAD Функции окон.

+0

Любопытный. Какую информацию вам не хватает? – CodyMR

Смежные вопросы