Существует ли элегантный способ подсчета доли года в диапазоне дат в SQL Server 2014? - PullRequest
0 голосов
/ 15 января 2020

Как указано выше, я хочу создать в моем наборе данных столбец, в котором указано, какой процент года находится в диапазоне дат.

Snapshot of data in excel

Это уже было сделано в Excel, но теперь я должен воспроизвести это в SQL. Вот типы данных столбца:

  • Yr1 int
  • Yr2 float
  • Yr3 float
  • Yr4 float
  • Начало периода datetime
  • Конец периода datetime
  • Индикатор периода varchar
  • Индикатор високосного года varchar
  • Длина периода с плавающей запятой
  • Год1 Заработать% int
  • Yr2 Заработать% float
  • Yr3 Заработать% float
  • Yr4 Заработать% float
  • Total Earn% float

Здесь SQL используется для генерации столбцов. Год1 Заработать% к сожалению не работает. Я получаю сообщение об ошибке: «Тип данных операнда datetime недопустим для оператора деления».

Есть ли способ вычислить это в SQL так же, как показано ниже?

      ,[Yr1]+1 as 'Yr2'
      ,[Yr2]+1 as 'Yr3'
      ,[Yr3]+1 as 'Yr4'
      ,dateadd(d,[INSRD PERIOD START],'1899-12-30') as 'Period Start'
      ,dateadd(d,[INSRD PERIOD END],'1899-12-30') as 'Period End'
      ,CASE WHEN MONTH([PERIOD START]) = MONTH([PERIOD END]) AND DAY([PERIOD START]) = DAY([PERIOD END])
            THEN 'Y'
            ELSE 'N'
       END AS 'Period Indicator'
      ,CASE WHEN ISDATE(CAST(YEAR([Period Start]) AS char(4)) + '0229') = 1 
                 OR 
                 ISDATE(CAST(YEAR([Period End]) AS char(4)) + '0229') = 1
            THEN 'Y' 
            ELSE 'N' 
       END as 'Leap Year Indicator'
      ,(([Period End]-([Period Start]-CASE WHEN [Period Indicator]='Y' 
                                          THEN 0 
                                          ELSE 1 
                                          END)))/(CASE WHEN [Leap Year Indicator]='N' 
                                                       THEN 365 
                                                       ELSE 366 
                                                       END) as 'Length of Period'
      ,(SELECT MAX(v) 
       FROM (VALUES (0),
        (((SELECT MIN(w) 
         FROM (VALUES ('2019-06-30'),
                      (CASE WHEN [Period Indicator]='N' 
                            THEN DATEADD(d,[Period End],'1899-12-30')
                            ELSE (DATEADD(DAY,-1,[Period End]))
                            END)
                       ,
                      (DATEFROMPARTS([Yr1],'12','31'))
              ) as value(w))-
                      (SELECT MAX(x) 
                       FROM (VALUES (DATEFROMPARTS([Yr1],'12','31')),
                                    (DATEADD(DAY,-1,[Period Start]))
                            ) as value(x)
                      )
        )/((CASE WHEN [Period Indicator]='N' 
                THEN dateadd(DAY,[Period End],'1899-12-30')
                ELSE DATEADD(DAY,-1,[Period End]) 
                END) 
                - (DATEADD(DAY,-1,[Period Start]))))
       ) as value(v)
       )  as 'Yr1 Earn %'
      ,[Yr2 Earn %] as 'Yr2 Earn %'
      ,[Yr3 Earn %] as 'Yr3 Earn %'
      ,[Yr4 Earn %] as 'Yr4 Earn %'
      ,[Yr1 Earn %]+[Yr2 Earn %]+[Yr3 Earn %]+[Yr4 Earn %] as 'Total Earn %'

РЕДАКТИРОВАТЬ: Вот копия формулы Excel, используемой для создания столбца Yr1 Earn% на скриншоте. z_eval = '2019-06-30'

= MAX (0, (MIN (z_eval, IF ($ G2 = "N", $ F2, $ F2-1), DATE (A2, 12,31)) - MAX (DATE (A2-> 1,12,31), $ E2-1)) / (IF ($ G2 = "N", $ F2, $ F2-1) - ($ E2- 1)))

РЕДАКТИРОВАТЬ: Спасибо всем за ваши полезные комментарии до сих пор. Я преобразовал все dates в ints с этим блоком кода для Yr1 Earn %. Все значения по умолчанию равны нулю. Не удается ли внешней функции MAX(v) проанализировать внутренние функции Max / Min?

,(SELECT MAX(v) 
 FROM (VALUES (0),
  (((SELECT MIN(w) 
   FROM (VALUES (DATEDIFF(d,'1899-12-30','2019-06-30')),
                (CASE WHEN [Period Indicator]='N' 
                      THEN DATEDIFF(d,'1899-12-30',[Period End])
                      ELSE (DATEDIFF(d,'1899-12-30',DATEADD(DAY,-1,[Period End])))
                      END)
                 ,
                (DATEDIFF(d,'1899-12-30',DATEFROMPARTS([Yr1],'12','31')))
        ) as value(w))-
                (SELECT MAX(x) 
                 FROM (VALUES (DATEDIFF(d,'1899-12-30',DATEFROMPARTS([Yr1],'12','31'))),
                              (DATEDIFF(d,'1899-12-30',DATEADD(DAY,-1,[Period Start])))
                      ) as value(x)
                )
  )/((CASE WHEN [Period Indicator]='N' 
           THEN DATEDIFF(d,'1899-12-30',DATEADD(DAY,[Period End],'1899-12-30'))
           ELSE DATEDIFF(d,'1899-12-30',DATEADD(DAY,-1,[Period End])) 
           END) 
           - (DATEDIFF(d,'1899-12-30',DATEADD(DAY,-1,[Period Start])))))
 ) as value(v)
 ) as 'Yr1 Earn %'

1 Ответ

0 голосов
/ 15 января 2020

SQL не воспроизводится, когда Select Max(v) FROM VALUES(....) as value(v) вложено в оператор выбора, как я делал выше. К сожалению, мне пришлось разбить их на отдельные части и объединить их во временные таблицы. Это не самое элегантное решение, но вполне может быть единственным решением без объединений. См. Приведенный ниже код для генерации столбцов.

Кроме того, при преобразовании дат из Excel в SQL предусмотрена корректировка на 2 дня.

Это объясняется далее здесь :

select *,
        (1.000000000000000*(SELECT MIN(w) 
        FROM (VALUES (DATEDIFF(d,'1899-12-30',[EVAL])),
                    (CASE WHEN [Period Indicator]='N' 
                          THEN DATEDIFF(d,'1899-12-30',[Period End])
                          ELSE (DATEDIFF(d,'1899-12-30',DATEADD(DAY,-1,[Period End])))
                          END),
                    (DATEDIFF(d,'1899-12-30',DATEFROMPARTS([Yr1],'12','31')))
        ) as value(w))) as 'Yr1 Earn % a',
        (1.000000000000000*(SELECT MAX(x) 
            FROM (VALUES (DATEDIFF(d,'1899-12-30',DATEFROMPARTS([Yr1]-1,'12','31'))),
                         (DATEDIFF(d,'1900-01-01',DATEADD(DAY,-1,[Period Start])))) 
            as value(x))) as 'Yr1 Earn % b',
        (1.000000000000000*(SELECT MIN(w) 
        FROM (VALUES (DATEDIFF(d,'1899-12-30',[EVAL])),
                    (CASE WHEN [Period Indicator]='N' 
                          THEN DATEDIFF(d,'1899-12-30',[Period End])
                          ELSE (DATEDIFF(d,'1899-12-30',DATEADD(DAY,-1,[Period End])))
                          END),
                    (DATEDIFF(d,'1899-12-30',DATEFROMPARTS([Yr2],'12','31')))
        ) as value(w))) as 'Yr2 Earn % a',
        (1.000000000000000*(SELECT MAX(x) 
            FROM (VALUES (DATEDIFF(d,'1899-12-30',DATEFROMPARTS([Yr2]-1,'12','31'))),
                         (DATEDIFF(d,'1900-01-01',DATEADD(DAY,-1,[Period Start])))) 
            as value(x))) as 'Yr2 Earn % b',
        (1.000000000000000*(SELECT MIN(w) 
        FROM (VALUES (DATEDIFF(d,'1899-12-30',[EVAL])),
                    (CASE WHEN [Period Indicator]='N' 
                          THEN DATEDIFF(d,'1899-12-30',[Period End])
                          ELSE (DATEDIFF(d,'1899-12-30',DATEADD(DAY,-1,[Period End])))
                          END),
                    (DATEDIFF(d,'1899-12-30',DATEFROMPARTS([Yr3],'12','31')))
        ) as value(w))) as 'Yr3 Earn % a',
        (1.000000000000000*(SELECT MAX(x) 
            FROM (VALUES (DATEDIFF(d,'1899-12-30',DATEFROMPARTS([Yr3]-1,'12','31'))),
                         (DATEDIFF(d,'1900-01-01',DATEADD(DAY,-1,[Period Start])))) 
            as value(x))) as 'Yr3 Earn % b' ,
        (1.000000000000000*(SELECT MIN(w) 
        FROM (VALUES (DATEDIFF(d,'1899-12-30',[EVAL])),
                    (CASE WHEN [Period Indicator]='N' 
                          THEN DATEDIFF(d,'1899-12-30',[Period End])
                          ELSE (DATEDIFF(d,'1899-12-30',DATEADD(DAY,-1,[Period End])))
                          END),
                    (DATEDIFF(d,'1899-12-30',DATEFROMPARTS([Yr4],'12','31')))
        ) as value(w))) as 'Yr4 Earn % a',
        (1.000000000000000*(SELECT MAX(x) 
            FROM (VALUES (DATEDIFF(d,'1899-12-30',DATEFROMPARTS([Yr4]-1,'12','31'))),
                         (DATEDIFF(d,'1900-01-01',DATEADD(DAY,-1,[Period Start])))) 
            as value(x))) as 'Yr4 Earn % b',
        (1.000000000000000*(CASE WHEN [Period Indicator]='N' 
                 THEN DATEDIFF(d,'1900-01-01',[Period End])
                 ELSE DATEDIFF(d,'1900-01-01',DATEADD(DAY,-1,[Period End])) 
                 END)) as 'Earn % c',
        (1.000000000000000*(DATEDIFF(d,'1900-01-01',DATEADD(DAY,-1,[Period Start]))))as 'Earn % d'
into #temptemp2
from #temptemp1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...