用 outerapply 填充
Filldown with outerapply
我的源数据如下
declare @dim as table
(
name varchar(10),period int
)
insert into @dim
select * from
(
values
('a', 202001),('a', 202002),('a', 202003),('a', 202004),
('a', 202005),('a', 202006),('a', 202007),('a', 202008),
('a', 202009),('a', 202010),('a', 202011),('a', 202012),
('b', 202001),('b', 202002),('b', 202003),('b', 202004),
('b', 202005),('b', 202006),('b', 202007),('b', 202008),
('b', 202009),('b', 202010),('b', 202011),('b', 202012)
) t (one, two)
declare @fact as table
(
name varchar(max),period bigint,val decimal(19, 2)
)
insert into @fact
select * from
(
values
('a', 202002, 100),
('a', 202005, 600),
('a', 202010, 700),
('b', 202004, 500),
('b', 202007, 600),
('b', 20208, 1000)
) t (one, two, three)
我想知道是否有可能在 outer-apply
中实现向下填充。我试过如下但没有用
select a.name,a.period,x.val, y.FD
from @dim a
outer apply (select * from @fact b where a.name=b.name and a.period=b.period) as x
outer apply (select max(x.val) over (partition by a.name order by a.period ASC ROWS UNBOUNDED PRECEDING)) as y (FD)
我之所以热衷于在 outer-apply
中实现向下填充,是因为我可以在同一查询中继续利用 outer-apply
中的向下填充列,继而 apply
到在没有任何临时 table 帮助的情况下创建进一步的计算列或转换,如下所示
select a.name,a.period,x.val, y.FD, z.bucket
from @dim a
outer apply (select * from @fact b where a.name=b.name and a.period=b.period) as x
outer apply (successful fill down) as y (FD)
outer apply (VALUES(CASE WHEN FD>1000 then 'bucket1' else 'bucket2' end) as z(bucket)
我想要的结果
姓名
时期
值
FD
一个
202001
空
空
一个
202002
100.00
100.00
一个
202003
空
100.00
一个
202004
空
100.00
一个
202005
600.00
600.00
一个
202006
空
600.00
一个
202007
空
600.00
一个
202008
空
600.00
一个
202009
空
600.00
一个
202010
700.00
700.00
一个
202011
空
700.00
一个
202012
空
700.00
b
202001
空
空
b
202002
空
空
b
202003
空
空
b
202004
500.00
500.00
b
202005
空
500.00
b
202006
空
500.00
b
202007
600.00
600.00
b
202008
空
600.00
b
202009
空
600.00
b
202010
空
600.00
b
202011
空
600.00
b
202012
空
600.00
这可以通过关注但在我不想要的 outer-apply
之外来实现。
select a.name,a.period,x.val, MAX(x.val) over (partition by a.name order by a.period ASC ROWS UNBOUNDED PRECEDING) as FD
from @dim a
outer apply (select * from @fact b where a.name=b.name and a.period=b.period) as x
您的问题是您将 MAX
window 函数放在 APPLY
.
中
当您使用 APPLY
时,将(逻辑上)为每一行评估整个子查询。因此,仅包含 select
的子查询只有一行,并且会根据外部 table.
的每一行进行评估
您不能以这种方式使用window函数。Window函数仅(逻辑上)求值在加入和分组之后,在 select
阶段和排序之前。 APPLY
进入连接阶段,这是较早的阶段。
Note that your first APPLY
can be rewritten as a simple LEFT JOIN
.
select
a.name,
a.period,
x.val,
FD = max(x.val) over
(partition by a.name
order by a.period ROWS UNBOUNDED PRECEDING)
from @dim a
left join @fact x on a.name = x.name and a.period = x.period
如果您希望 MAX
在查询的其他部分使用,您 必须 将它放在派生的 table.
select *,
SomeOtherCalculationInvolvingFD
from (
select
a.name,
a.period,
x.val,
FD = max(x.val) over
(partition by a.name
order by a.period ROWS UNBOUNDED PRECEDING)
from @dim a
left join @fact x on a.name = x.name and a.period = x.period
) t
我给你一个提示:APPLY
非常有用,但不要到处敲钉子。了解它的工作原理,适当使用。
我的源数据如下
declare @dim as table
(
name varchar(10),period int
)
insert into @dim
select * from
(
values
('a', 202001),('a', 202002),('a', 202003),('a', 202004),
('a', 202005),('a', 202006),('a', 202007),('a', 202008),
('a', 202009),('a', 202010),('a', 202011),('a', 202012),
('b', 202001),('b', 202002),('b', 202003),('b', 202004),
('b', 202005),('b', 202006),('b', 202007),('b', 202008),
('b', 202009),('b', 202010),('b', 202011),('b', 202012)
) t (one, two)
declare @fact as table
(
name varchar(max),period bigint,val decimal(19, 2)
)
insert into @fact
select * from
(
values
('a', 202002, 100),
('a', 202005, 600),
('a', 202010, 700),
('b', 202004, 500),
('b', 202007, 600),
('b', 20208, 1000)
) t (one, two, three)
我想知道是否有可能在 outer-apply
中实现向下填充。我试过如下但没有用
select a.name,a.period,x.val, y.FD
from @dim a
outer apply (select * from @fact b where a.name=b.name and a.period=b.period) as x
outer apply (select max(x.val) over (partition by a.name order by a.period ASC ROWS UNBOUNDED PRECEDING)) as y (FD)
我之所以热衷于在 outer-apply
中实现向下填充,是因为我可以在同一查询中继续利用 outer-apply
中的向下填充列,继而 apply
到在没有任何临时 table 帮助的情况下创建进一步的计算列或转换,如下所示
select a.name,a.period,x.val, y.FD, z.bucket
from @dim a
outer apply (select * from @fact b where a.name=b.name and a.period=b.period) as x
outer apply (successful fill down) as y (FD)
outer apply (VALUES(CASE WHEN FD>1000 then 'bucket1' else 'bucket2' end) as z(bucket)
我想要的结果
姓名 | 时期 | 值 | FD |
---|---|---|---|
一个 | 202001 | 空 | 空 |
一个 | 202002 | 100.00 | 100.00 |
一个 | 202003 | 空 | 100.00 |
一个 | 202004 | 空 | 100.00 |
一个 | 202005 | 600.00 | 600.00 |
一个 | 202006 | 空 | 600.00 |
一个 | 202007 | 空 | 600.00 |
一个 | 202008 | 空 | 600.00 |
一个 | 202009 | 空 | 600.00 |
一个 | 202010 | 700.00 | 700.00 |
一个 | 202011 | 空 | 700.00 |
一个 | 202012 | 空 | 700.00 |
b | 202001 | 空 | 空 |
b | 202002 | 空 | 空 |
b | 202003 | 空 | 空 |
b | 202004 | 500.00 | 500.00 |
b | 202005 | 空 | 500.00 |
b | 202006 | 空 | 500.00 |
b | 202007 | 600.00 | 600.00 |
b | 202008 | 空 | 600.00 |
b | 202009 | 空 | 600.00 |
b | 202010 | 空 | 600.00 |
b | 202011 | 空 | 600.00 |
b | 202012 | 空 | 600.00 |
这可以通过关注但在我不想要的 outer-apply
之外来实现。
select a.name,a.period,x.val, MAX(x.val) over (partition by a.name order by a.period ASC ROWS UNBOUNDED PRECEDING) as FD
from @dim a
outer apply (select * from @fact b where a.name=b.name and a.period=b.period) as x
您的问题是您将 MAX
window 函数放在 APPLY
.
当您使用 APPLY
时,将(逻辑上)为每一行评估整个子查询。因此,仅包含 select
的子查询只有一行,并且会根据外部 table.
您不能以这种方式使用window函数。Window函数仅(逻辑上)求值在加入和分组之后,在 select
阶段和排序之前。 APPLY
进入连接阶段,这是较早的阶段。
Note that your first
APPLY
can be rewritten as a simpleLEFT JOIN
.
select
a.name,
a.period,
x.val,
FD = max(x.val) over
(partition by a.name
order by a.period ROWS UNBOUNDED PRECEDING)
from @dim a
left join @fact x on a.name = x.name and a.period = x.period
如果您希望 MAX
在查询的其他部分使用,您 必须 将它放在派生的 table.
select *,
SomeOtherCalculationInvolvingFD
from (
select
a.name,
a.period,
x.val,
FD = max(x.val) over
(partition by a.name
order by a.period ROWS UNBOUNDED PRECEDING)
from @dim a
left join @fact x on a.name = x.name and a.period = x.period
) t
我给你一个提示:APPLY
非常有用,但不要到处敲钉子。了解它的工作原理,适当使用。