2016-05-08 4 views
-1

У меня есть следующий формат таблицы;Преобразование флагов месяца в даты в SQL

tripID 
departureDate (date) 
availableJan (bit) 
availableFeb (bit) 
availableMar (bit) 
availableApr (bit) 
availableMay (bit) 
availableJun (bit) 
availableJul (bit)  
availableAug (bit)  
availableSep (bit) 
availableOct (bit) 
availableNov (bit) 
availableDec (bit) 

Поездки будут либо выбора любого из доступных «» флагов или дату вылета.

Что я пытаюсь сделать, это функция базы данных, которая преобразует флаги в полезную дату на основе текущей даты.

Так что, если поездка имеет нулевую дату вылета и доступен Август, сентябрь, октябрь, то учитывая текущую дата 8 мая 2016 года я хотел бы функцию, чтобы вернуть дату 1-го августа 2016 года

логика заключается в том, что функция возвращает первый день следующего доступного месяца с текущей даты.

Другие примеры, например. сегодня дата 06/06/2016;

месяц флаги, как истинные: январь, февраль, март
Ожидаемые результаты: 1-Jan 2017

месяц флаги как истинные: Ян, Июнь
Ожидаемые результаты: 1-е июня 2016

месяц флаги, как истинный : июнь, июль, август, декабрь
Ожидаемые результаты: 1 июня 2016

я пошел по кругу, пытаясь большим, если заявления, временные таблицы, но я задавался вопросом, есть ли более умный способ достижения этой ТНА t не убивает процессор.

Любая помощь очень ценится,

Спасибо,

Ник

ответ

0

Всякий раз, когда вы думаете о написании кучи утверждений СОЮЗ, подобных этому, подумайте fold. То, что вы хотите, - это минимальная доступная дата для поездки. Итак, сначала создайте даты, затем поместите их в столбец, затем выберите минимальный. Весь shebang может быть одним в одном select.

Сначала сделайте себе статическую таблицу из 12 строк с целыми числами 1-12. Назовем это Months.Затем

with start as (
    select dt = dateadd(YEAR, 
         datediff(YEAR, '20000101', getdate()), 
         '20000101') 
) 
select TripId, min(departure) as Departure 
    select TripID 
     , case month 
      when 1 then case availableJan 
         when 1 then dateadd(MONTH,month,start.dt) end 
      when 2 then case availableFeb 
         when 1 then dateadd(MONTH,month,start.dt) end 
      --- 10 more times -- 
      end as departure 
    from itinerary cross join Months 
) as M 
where departure >= getdate() 
group by TripID 

Этот метод известен как складной и может рассматриваться как противоположность поворотными (т.е. расположения строк в виде столбцов). Для СУБД обычно намного эффективнее, чем последовательность UNIONS, потому что, несмотря на наличие большого количества SQL, есть только одно упоминание о таблице. Результаты могут быть получены путем выполнения одного прохода по данным; единственной проблемой сервера является то, что делать с каждой строкой. Это также менее многословно и, как только вы привыкнете к нему, легко распознать.

+0

Умный ответ и хорошие рассуждения! благодаря – Grenville

0

Первый доступный первый месяца начиная с сегодняшнего дня

with start as (
    select dt = dateadd(YEAR,datediff(YEAR,'20000101',getdate()),'20000101') 
) 
select tripID 
, firstDate = (
    select min(d) 
    from (
     select d = start.dt where availableJan = 1 
     union all 
     select d = dateadd(MONTH,1,start.dt) where availableFeb = 1 
     union all 
     select d = dateadd(MONTH,2,start.dt) where availableMar = 1 
     -- ... 
    ) 
    where d >= getdate()) 
from mytable 
join start; 
+0

Спасибо, serg, я получаю ошибку: идентификатор с несколькими частями «start.dt» не может быть связан. Вы имели в виду присоединиться к столам? – Grenville

+0

Мой плохой, исправленный. – Serg

0

На основании ответа Serg в (спасибо!), Мне удалось достичь желаемого результата следующим образом;

DECLARE @firstDayOfCurrentYear date = dateadd(YEAR,datediff(YEAR,'20000101',getdate()),'20000101') 
DECLARE @firstOfCurrenyMonth date = CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(GETDATE())-1),GETDATE()),101) 

SELECT 
    itinerary.*,    
    COALESCE 
    (
     departureDate, 
     (
      SELECT MIN(d) FROM 
      (
       SELECT @firstDayOfCurrentYear     AS d WHERE availableJan = 1 UNION ALL 
       SELECT DATEADD(MONTH,1,@firstDayOfCurrentYear) AS d WHERE availableFeb = 1 UNION ALL 
       SELECT DATEADD(MONTH,2,@firstDayOfCurrentYear) AS d WHERE availableMar = 1 UNION ALL 
       SELECT DATEADD(MONTH,3,@firstDayOfCurrentYear) AS d WHERE availableApr = 1 UNION ALL 
       SELECT DATEADD(MONTH,4,@firstDayOfCurrentYear) AS d WHERE availableMay = 1 UNION ALL 
       SELECT DATEADD(MONTH,5,@firstDayOfCurrentYear) AS d WHERE availableJun = 1 UNION ALL 
       SELECT DATEADD(MONTH,6,@firstDayOfCurrentYear) AS d WHERE availableJul = 1 UNION ALL 
       SELECT DATEADD(MONTH,7,@firstDayOfCurrentYear) AS d WHERE availableAug = 1 UNION ALL 
       SELECT DATEADD(MONTH,8,@firstDayOfCurrentYear) AS d WHERE availableSep = 1 UNION ALL 
       SELECT DATEADD(MONTH,9,@firstDayOfCurrentYear) AS d WHERE availableOct = 1 UNION ALL 
       SELECT DATEADD(MONTH,10,@firstDayOfCurrentYear) AS d WHERE availableNov = 1 UNION ALL 
       SELECT DATEADD(MONTH,11,@firstDayOfCurrentYear) AS d WHERE availableDec = 1 UNION ALL 
       SELECT DATEADD(MONTH,12,@firstDayOfCurrentYear) AS d WHERE availableJan = 1 UNION ALL 
       SELECT DATEADD(MONTH,13,@firstDayOfCurrentYear) AS d WHERE availableFeb = 1 UNION ALL 
       SELECT DATEADD(MONTH,14,@firstDayOfCurrentYear) AS d WHERE availableMar = 1 UNION ALL 
       SELECT DATEADD(MONTH,15,@firstDayOfCurrentYear) AS d WHERE availableApr = 1 UNION ALL 
       SELECT DATEADD(MONTH,16,@firstDayOfCurrentYear) AS d WHERE availableMay = 1 UNION ALL 
       SELECT DATEADD(MONTH,17,@firstDayOfCurrentYear) AS d WHERE availableJun = 1 UNION ALL 
       SELECT DATEADD(MONTH,18,@firstDayOfCurrentYear) AS d WHERE availableJul = 1 UNION ALL 
       SELECT DATEADD(MONTH,19,@firstDayOfCurrentYear) AS d WHERE availableAug = 1 UNION ALL 
       SELECT DATEADD(MONTH,20,@firstDayOfCurrentYear) AS d WHERE availableSep = 1 UNION ALL 
       SELECT DATEADD(MONTH,21,@firstDayOfCurrentYear) AS d WHERE availableOct = 1 UNION ALL 
       SELECT DATEADD(MONTH,22,@firstDayOfCurrentYear) AS d WHERE availableNov = 1 UNION ALL 
       SELECT DATEADD(MONTH,23,@firstDayOfCurrentYear) AS d WHERE availableDec = 1 
      ) AS dateTable where d >= @firstOfCurrenyMonth 
     ) 
    ) AS inclusiveDepartureDate 
FROM 
    itinerary 

Этот счет для того, когда месяц часть пути через год, так что дата следующего вылета в следующем году (то есть я союзные 24 строки, а не только 12).

Я использую COALESCE, чтобы выполнить эту операцию только в том случае, если нормальная дата отъезда равна нулю.

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