2015-09-23 4 views
-1

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

Мне нужно найти начало последнего и текущего финансового месяца.

Некоторые примеры:

если сегодня 23 сентября 2015 я должен получить 29 июля и 26 августа, так как текущий финансовый год проходит с 26 августа по 29 сентября.

Если сегодня 30 сентября 2015 года, мне нужно получить с 26 августа по 30 сентября.

У меня разные клиенты с разными определениями, и это означает, что некоторые из них используют среду, а другие используют понедельник, поэтому мне нужен этот день для параметра, например, понедельник = 1 и среда = 3. Я называю это FDOM, FirstDayOfMonth.

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

DECLARE @BASE AS DateTime = '19000101 00:00' 

DECLARE @FDOM AS INT = 3 --Wednesday 

DECLARE @Datevalue AS DATE = GETDATE() 

SET DATEFIRST @FDOM 

select DATEADD(D,1-(DATEPART(dw,DATEADD(D,-1,DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @Datevalue) , @BASE)))),DATEADD(D,-1,DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @Datevalue) , @BASE))) 

Это дает мне первую среду после того, как последний вторник последнего месяца, и это было бы правильно с 1 сентября по 29 сентября (это дает 26 августа), как «начало текущего финансового месяца». Но это было бы неправильно 30 сентября, так как это должно было дать 30 сентября, а также не так с 26 августа до конца августа, как это должно было дать 26 августа, а вместо этого дается 29 июля.

+0

Так финансового апреля 2015 был 1 апреля до 28 апреля (но 'd хотите найти даты 1 апреля и 29 апреля)? –

+0

Если сегодня с 29 апреля по 26 мая (оба включительно) мне нужно получить 1 апреля-29 апреля, да –

+0

Другими словами: Я создаю подписку на SSRS, и когда я запускаю отчет, мне нужно, чтобы он был о последний полный финансовый месяц. Так что, если я запускаю его с 29 апреля по 26 мая включительно, то последний полный финансовый месяц должен быть Финансовым апрелем, который будет проходить с 1 апреля включительно до 29 апреля. Исключительно –

ответ

0

После долгих усилий мне удалось найти выражение, которое не использует CTE, как я не уверен, что я не могу использовать СТ во всех местах, я должен буду использовать это.

Так что вначале я понимаю, что с CASE, если дата, которую я рассматриваю, находится до или после последней среды месяца, к которой она принадлежит. Затем я возвращаю последний сеанс из двух и месяц назад или в последнюю среду месяца месяца и месяца. Это работает также с изменением FDOM, и я проверил его в течение нескольких месяцев этого года. Кажется, он всегда работает. Возможно, использование EOMonth сократит его, но я должен проверить, могу ли я использовать его на своем сервере.

Я сожалею, я только что указано в качестве требования, что я не могу использовать КТР только в комментариях, но спасибо за вашу помощь

DECLARE @datevalue AS Datetime = getdate() 
DECLARE @BASE AS DateTime = '19000101 00:00' 
DECLARE @FDOM AS INT = 3 --1 is for Monday 
SET DATEFIRST @FDOM 

SELECT CASE WHEN (@datevalue < DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) + 1, @BASE))),DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) + 1, @BASE))) 
     THEN(DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) - 1, @BASE))),DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) - 1, @BASE))) 
     ELSE(DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) - 0, @BASE))),DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) - 0, @BASE))) 
     END AS [Start of Last Financial Month] 
,CASE WHEN (@datevalue < DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) + 1, @BASE))),DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) + 1, @BASE))) 
     THEN(DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) + 0, @BASE))),DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) + 0, @BASE))) 
     ELSE(DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) + 1, @BASE))),DATEADD(MONTH, DATEDIFF(MONTH, @BASE, @datevalue) + 1, @BASE))) 
     END AS [Start of Current Financial Month] 
0

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

declare @FDOM int 
set @FDOM = 3 --Wednesday. 0 = Sunday, 6 = Saturday 

declare @KnownDay datetime 
set @KnownDay = DATEADD(day,@FDOM - 1,'20150301') --Offset from a "known good" Sunday to the day before FDOM 
declare @EOLastDec datetime 
set @EOLastDec = DATEADD(year,DATEDIFF(year,'20010101',GETDATE()),'200') 
declare @Today datetime 
set @Today = DATEADD(day,DATEDIFF(day,0,GETDATE()),0) --You can change this to test other key dates 

;With Numbers(n) as (--If you have a numbers table, you can skip this CTE 
    select ROW_NUMBER() OVER (ORDER BY so1.object_id) - 1 
    from sys.objects so1 cross join sys.objects so2 
), LastOfMonths as (
    select DATEADD(month,n,@EOLastDec) as LOM 
    from Numbers 
    where n between 0 and 13 
), LastImportant as (
    select DATEADD(day,-n,LOM) as EOFMonth 
    from LastOfMonths cross join Numbers 
    where n between 0 and 6 and 
    DATEPART(weekday,DATEADD(day,-n,LOM)) = DATEPART(weekday,@KnownDay) 
) 
select DATEADD(day,1,li0.EOFMonth) as StartOfMonth,DATEADD(day,1,li1.EOFMonth) as EndOfMonth 
from 
    LastImportant li1 
     cross join 
    LastImportant li2 
     left join 
    LastImportant li1_anti 
     on 
      li1.EOFMonth < li1_anti.EOFMonth and 
      li1_anti.EOFMonth <= @Today 
     left join 
    LastImportant li2_anti 
     on 
      li2.EOFMonth > li2_anti.EOFMonth and 
      li2_anti.EOFMonth >= @Today 
     inner join 
    LastImportant li0 
     on 
      li0.EOFMonth < li1.EOFMonth 
     left join 
    LastImportant li0_anti 
     on 
      li0_anti.EOFMonth < li1.EOFMonth and 
      li0.EOFMonth < li0_anti.EOFMonth 
where 
    li1.EOFMonth <= @Today and 
    li2.EOFMonth >= @Today and 
    li1_anti.EOFMonth is null and 
    li2_anti.EOFMonth is null and 
    li0_anti.EOFMonth is null 

Будем надеяться, что КТЭ достаточно обоснованы. Мы генерируем таблицу чисел, а затем вычисляем последний день каждого месяца, и оттуда мы делаем шаг назад до 6 дней назад, чтобы определить день подходящего типа (т.е. вторник, если @FDOM равно 3)

я первоначально имел более простой окончательный запрос, используя только li1 и li2li1_anti и li2_anti), но понял, что запрос был просто найти текущий финансовый год - поэтому я добавил еще пару присоединяется (используя li0 и li0_anti), чтобы найти начало предыдущего финансового месяца.

0

Попробуйте это. Вы можете использовать функцию EOMONTH, чтобы получить конец месяца на Sql Server 2012 или выше.

Click to see the fiddle demo.

DECLARE @date DATETIME = GETDATE() 
DECLARE @LastMonthEnd DATETIME = DATEADD(day, -1, DATEADD(month, DATEDIFF(month, 0, @date), 0)) 
DECLARE @CurrentMonthEnd DATETIME = DATEADD(day, -1, DATEADD(month, DATEDIFF(month, 0, @date) + 1, 0)) 


SET DATEFIRST 1 

;WITH CTE1 AS 
(
    SELECT 1 number, DATEPART(WEEKDAY, @LastMonthEnd) FirstDay, 
        DATEPART(WEEKDAY, @CurrentMonthEnd) LastDay  
    UNION ALL 

    SELECT 1+number, DATEPART(WEEKDAY, DATEADD(DAY, -number, @LastMonthEnd)), 
         DATEPART(WEEKDAY, DATEADD(DAY, -number, @CurrentMonthEnd)) 
    FROM CTE1 
    WHERE number < 7 
) 
SELECT DATEADD(DAY, -(SELECT Number FROM CTE1 WHERE FirstDay = 3), @LastMonthEnd) StartDate, 
     DATEADD(DAY, -(SELECT Number FROM CTE1 WHERE LastDay = 3), @CurrentMonthEnd) EndDate 
0

Вычислить начальную дату от предыдущего месяца и в последний день из текущего месяца и использовал КТР для создания всех дат между ними. Позже вы получите MAX рабочий день с обоих месяцев.

DECLARE @CurrentDate DATE = '2015-08-23' 
DECLARE @StartDate  DATE, 
     @EndDate  DATE, 
     @MonthEnd  INT = 3 

-- Get the first day from previous month and last day from current month 
SELECT @StartDate  = DATEADD(MONTH , DATEDIFF(MONTH, 0, @CurrentDate)-1, 0), 
     @EndDate  = DATEADD(SECOND,-1, 
          DATEADD(MONTH , DATEDIFF(MONTH, 0, @CurrentDate)+1,0)) 

;WITH Calendar AS 
(  -- Generate all dates between @StartDate and @EndDate 
     SELECT @StartDate [Date] 
     UNION ALL 
     SELECT DATEADD(D, +1, Calendar.[Date]) 
     FROM Calendar 
     WHERE Calendar.[Date] < @EndDate 
) 
SELECT DATEADD(DAY, +1, MAX(StartDate.[Date])) StartDate, 
     DATEADD(DAY, +1, MAX(EndDate .[Date])) EndDate 
FROM Calendar StartDate, 
     Calendar EndDate 
WHERE -- Get the max weekday from previous month 
     DATEPART(MONTH , StartDate.[Date]) = DATEPART(MONTH, @StartDate) AND 
     DATEPART(WEEKDAY, StartDate.[Date]) = @MonthEnd AND 
     -- Get the max weekday from current month 
     DATEPART(MONTH , EndDate .[Date]) = DATEPART(MONTH, @EndDate) AND 
     DATEPART(WEEKDAY, EndDate .[Date]) = @MonthEnd