sql-server - 使用 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
创建进一步的计算列或转换,而无需任何临时表的帮助,如下所示
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
窗口函数放在APPLY
.
当您使用 时APPLY
,会(逻辑上)为每一行评估整个子查询。因此,仅包含 a 的子查询只有select
一行,并且对外部表的每一行进行评估。
您不能以这种方式使用窗口函数。仅(逻辑上)在加入和分组之后、select
阶段中和排序之前评估窗口函数。出现APPLY
在较早的加入阶段。
请注意,您的第一个
APPLY
可以重写为简单的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
查询的其他部分使用 ,则必须将其放在派生表中。
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
非常有用,但不要到处敲击每个钉子。了解它的工作原理,适当使用。
推荐阅读
- ruby-on-rails - ActiveModelSerializer 只显示关联的 id
- css - Flexbox 列,子项在 Edge 中超出范围
- elasticsearch - 如何基于metricbeat创建节拍
- sql - 将列从表添加到表
- javascript - NextJS + Express + Now 部署。无法启动,甚至 Demo 也无法启动
- javascript - 如何从nodeJS中的查询块中获取变量?
- node.js - NodeJS存储你需要解密和读取的加密数据库密码,而不是用户密码?
- apache - apache的neo4j反向代理配置
- javascript - 意外的令牌,预期的,用于 seletedValues.filter 方法
- wordpress - 在 WordPress 中重置密码后获取新的哈希密码