Как рассчитать среднее значение переменных на сервере SQL - PullRequest
0 голосов
/ 31 января 2020

Я пытаюсь вычислить диапазоны дат между строками и затем получить среднее значение.

declare @date0 date = (
  select top 1 my_date 
  from someTable 
  order by my_date desc)
declare @date1 date = (
  select my_date 
  from someTable 
  order by my_date desc
  offset 1 rows 
  fetch next 1 row only)
declare @date2 date = (
  select my_date 
  from someTable 
  order by my_date desc
  offset 2 rows 
  fetch next 1 row only)
declare @date3 date = (
  select my_date 
  from someTable 
  order by my_date desc
  offset 3 rows 
  fetch next 1 row only)

select 
[Range 1]   = dateDiff(day, @date1, @date0),
[Range 2]   = dateDiff(day, @date2, @date1),
[Range 3]   = dateDiff(day, @date3, @date2),
[Avg Range] = avg(
                nullIf(@date0, 0), 
                nullIf(@date1, 0), 
                nullIf(@date2, 0), 
                nullIf(@date3, 0)
              )

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

Однако я не уверен, как справиться со средним. Похоже, что функция должна работать с таблицей, а не с массивом, но у меня возникли проблемы с вставкой переменных в столбец временной таблицы.

Как получить среднее из этих диапазонов (не включая range = 0)

Ответы [ 3 ]

1 голос
/ 31 января 2020

Используйте UNION ALL, чтобы вернуть строку для каждого случая:

select avg(t.[Range]) [Avg Range]
from (
  select dateDiff(day, @date1, @date0) [Range]
  union all
  select dateDiff(day, @date2, @date1)
  union all
  select dateDiff(day, @date3, @date2)
) t
where t.[Range] <> 0 
1 голос
/ 31 января 2020

AVG - агрегатная функция, предназначенная для использования с GROUP BY или windows. Вы можете просто сделать математику в своем запросе:

select 
[Range 1]   = dateDiff(day, @date1, @date0),
[Range 2]   = dateDiff(day, @date2, @date1),
[Range 3]   = dateDiff(day, @date3, @date2),
[Avg Range] = (
               nullIf(@date0, 0) +
               nullIf(@date1, 0) + 
               nullIf(@date2, 0) + 
               nullIf(@date3, 0)
              ) /
              (
               CASE WHEN @date0 IS NULL THEN 0 ELSE 1 END +
               CASE WHEN @date1 IS NULL THEN 0 ELSE 1 END +
               CASE WHEN @date2 IS NULL THEN 0 ELSE 1 END +
               CASE WHEN @date3 IS NULL THEN 0 ELSE 1 END
              )
0 голосов
/ 01 февраля 2020

Нет причин использовать четыре разных запроса:

with dates as (
    select
        row_number() over (order by my_date desc) rn,
        datediff(days, lag(my_date) over (order by my_date desc), my_date) diff
    from T
)
select avg(nullif(diff, 0)) from dates where rn <= 3;

или

with dates as (
    select
        datediff(days, lag(my_date) over (order by my_date desc), my_date) diff
    from T
    order by my_date desc
    fetch next three rows only
)
select avg(nullif(diff, 0)) from dates;

Использование distinct также позволит вам легко получить первые три даты и не будет возиться с nullif().

with dates as (
    select distinct
        datediff(days, lag(my_date) over (order by my_date desc), my_date) diff
    from T
    order by my_date desc
    fetch next three rows only
)
select avg(diff) from dates;
...