如何计算 SQL 服务器中变量的平均值
How to calculate average of variables in SQL Server
我正在尝试计算行之间的日期范围,然后计算平均值。
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)
)
范围计算工作正常,但有点笨拙。
但是,我不确定如何处理平均值。看起来该函数应该 运行 针对 table 而不是数组,但是我在将变量插入临时 table 列时遇到了问题。
如何获得这些范围的平均值(不包括 range = 0
)?
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
)
使用 UNION ALL 为每种情况 return 一行:
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
没有理由使用四个不同的查询:
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;
我正在尝试计算行之间的日期范围,然后计算平均值。
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)
)
范围计算工作正常,但有点笨拙。
但是,我不确定如何处理平均值。看起来该函数应该 运行 针对 table 而不是数组,但是我在将变量插入临时 table 列时遇到了问题。
如何获得这些范围的平均值(不包括 range = 0
)?
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
)
使用 UNION ALL 为每种情况 return 一行:
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
没有理由使用四个不同的查询:
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;