2017-01-11 13 views
3

Мне нужна помощь с SQL Server 2012, которая пытается рассчитать поле лет старения для отчета.Расчет возраста лет в SQL

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

StartDateTime     EndDateTime 

2006-10-10 16:08:13.523  2008-04-11 00:00:00.000 
2016-05-11 13:03:48.093  2016-06-16 00:00:00.000 
2016-08-01 12:44:42.990  2016-08-01 00:00:00.000 
2016-05-20 17:33:27.957  2016-05-25 00:00:00.000 
2006-10-19 21:41:41.350  NULL 

я в настоящее время пытается сделать поле AgingYears для расчета Старение лет между обоими полями (как можно точнее .) И когда EndDateTime NULL, он должен рассчитать разницу между GETDATE() и StartDateTime. Когда StartDateTime больше, чем EndDateTime (который я не знаю, почему у меня есть некоторые данные, подобные этому, но я это делаю), тогда он должен просто вернуться обратно.

Я пробовал делать код на основе сайтов, которые я нашел, но это не помогает мне много, и это, где я застрял:

DATEDIFF(YY, StartDateTime, EndDateTime) - 
    CASE 
     WHEN DATEADD(YY,DATEDIFF(YY,StartDateTime, EndDateTime),StartDateTime) 
      > A.[END_DTTM] 
     THEN DATEDIFF(YY, StartDateTime, EndDateTime)- 1 
     ELSE DATEDIFF(YY, StartDateTime, EndDateTime) 
    END AS AgeInYears, 

Любая помощь с моим кодом было бы весьма признателен.

+0

Можете ли вы показать желаемые результаты из данных образцов? – Aducci

+0

Возможный дубликат [Как рассчитать возраст (в годах) на основе даты рождения и getDate()] (http://stackoverflow.com/questions/1572110/how-to-calculate-age-in-years-based- on-date-of-birth-and-getdate) –

+1

@JeremyDanyow Похоже, что большинство ответов на этот другой вопрос довольно сложны и, возможно, неправильны, хотя я уверен, что есть и другие, у которых есть подходы к вычислительной среде (например, независимо от языка.) – shawnt00

ответ

2

Будьте осторожны, високосные годы. Как вы хотите, чтобы с 29 февраля по 28 февраля обращались?

case 
    when year(coalesce(EndDateTime, getdate()) > year(StartDateTime) 
    then 
     datediff(year, StartDateTime, coalesce(EndDateTime, getdate())) - 
     case 
      when 
       EndDateTime is not null and 
        datepart(month, EndDateTime) < datepart(month, StartDateTime) 
       or datepart(month, EndDateTime) = datepart(month, StartDateTime) 
       and datepart(day, EndDateTime) < datepart(day, StartDateTime) 
      then 1 
      when 
       EndDateTime is null and 
        datepart(month, getdate()) < datepart(month, StartDateTime) 
       or datepart(month, getdate()) = datepart(month, StartDateTime) 
       and datepart(day, getdate()) < datepart(day, StartDateTime) 
      then 1 
      else 0 
     end 
    else 0 
end 

Я разделил EndDateTime и getdate() случаев в основном потому, что это выглядело лучше без полосы прокрутки на длинных линиях.

Вот один из способов изменить эту логику и уловить состояние високосного дня, рассматривая его как полный год, даже если даты не совпадают строго. Вам нужно будет дублировать это выражение (замените getdate() for EndDateTime everywhere except the на null) в обеих ветвях, если вы сохраните «разделенную» логику так, как я ее написал выше.

  when 
       EndDateTime is not null and 
        datepart(month, EndDateTime)  < datepart(month, StartDateTime) 
       or datepart(month, EndDateTime)  = datepart(month, StartDateTime) 
       and datepart(day, EndDateTime)  < datepart(day, StartDateTime) 
       and not -- here's one way to catch the leap day condition 
       (
        -- adding one day this way is deprecated and only works with datetime 
        and datepart(month, StartDateTime + 1) > datepart(month, StartDateTime) 
        and datepart(month, EndDateTime + 1) > datepart(month, EndDateTime) 
       ) 

http://rextester.com/SBH69843

Btw, как только вы понимаете, что подход есть способ уплотнить ту же логику, используя арифметические операции над числами в формате ГГГГММДД.

(
cast(convert(varchar(8), @EndDateTime, 120) as int) - 
cast(convert(varchar(8), @StartDateTime, 120) as int) 
)/10000 

Вся сложная логика, приведенная выше, просто заимствует из места года в вычитании. Это почти то же самое.

+0

Это выглядит сложнее, чем необходимо. –

+0

Это совсем не сложно. Это типичный способ сортировки дат (из разных лет) сначала по месяцам, а затем по дням месяца. – shawnt00

1

Я думаю, что это должно быть так:

SELECT StartDate 
    , EndDate 
    , CASE 
     WHEN DATEDIFF(YY, StartDate, ISNULL(EndDate, GETDATE())) < 0 
      THEN 0 
     ELSE DATEDIFF(YY, StartDate, ISNULL(EndDate, GETDATE())) 
     END AS AgingYears 
FROM YourTableName