将月标志转换为SQL中的日期

时间:2016-05-08 20:15:36

标签: sql sql-server

我有以下表格格式;

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月,9月,10月可用,则当前日期为2016年5月8日。我希望功能返回2016年8月1日。

此处的逻辑是该函数返回当前日期下一个可用月份的第一天。

更多例子,例如今天是06/06/2016;

月旗为真:1月,2月,3月 预计产量:2017年1月1日

月旗为真:Jan,Jun
预期产出:2016年6月1日

月旗为真:6月,7月,8月,12月 预期产出:2016年6月1日

我已经绕过圈子尝试大的if语句,临时表但我想知道是否有更聪明的方法来实现这个并不会杀死处理器。

任何帮助非常感谢,

谢谢,

尼克

3 个答案:

答案 0 :(得分: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;

答案 1 :(得分: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只在正常的departureDate为空时才执行此操作。

答案 2 :(得分:0)

每当你想到写一堆像那样的UNION语句时,想想 fold 。您想要的是旅行的最短可用日期。因此,首先制作日期,然后将它们放在一列中,然后选择最小的一个。整个shebang可以是一对一select声明。

首先,让自己成为一个包含整数1-12的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

此技术称为 folding ,可能被认为与 pivoting 相反(即将行排列为列)。 DBMS执行通常比一系列UNIONS更有效,因为 - 即使有很多SQL - 只有一个提到表。通过对数据进行单次传递可以产生结果;服务器唯一的问题是如何处理每一行。它也不那么罗嗦了,一旦你习惯了它,一个容易识别的习语。