window 函数中的 PostgreSQL IGNORE NULLS
PostgreSQL IGNORE NULLS in window functions
左侧面板数据没有 IGNORE NULLS。
在右侧面板数据上使用 IGNORE NULLS.
所以我需要在 PostgreSQL 中获得正确的变体
需要在 PostgreSQL 的 window 函数(LEAD 和 LAG)中模拟 Oracle IGNORE NULLS。
SELECT empno,
ename,
orig_salary,
LAG(orig_salary, 1, 0) IGNORE NULLS OVER (ORDER BY orig_salary) AS sal_prev
FROM tbl_lead;
如果有NULL,应该return最新的非空值。
我已经通过 PostgreSQL 用户定义的聚合函数尝试过,但是很难理解它的方法https://www.postgresql.org/docs/9.6/static/sql-createaggregate.html
解决方案不能通过WITH子句或子查询来实现,因为它用于复杂查询。
聚合有点复杂,因为你必须存储两个以前的值。可以使用数组作为 state-data
和最终函数来完成:
create or replace function my_lag_trans_fun(numeric[], numeric)
returns numeric[] language plpgsql as $$
begin
if [2] is not null then
[1]:= [2];
[2]:= ;
end if;
return ;
end $$;
create or replace function my_lag_final_fun(numeric[])
returns numeric language sql as $$
select [1];
$$;
create aggregate my_lag(numeric) (
sfunc = my_lag_trans_fun,
stype = numeric[],
initcond = '{0,0}',
finalfunc = my_lag_final_fun
);
用法:
with my_table(name, salary) as (
values
('A', 100),
('B', 200),
('C', 300),
('D', null),
('E', null),
('F', null)
)
select
name, salary,
lag(salary, 1, 0) over (order by salary) prev_salary,
my_lag(salary) over (order by salary) my_prev_salary
from my_table;
name | salary | prev_salary | my_prev_salary
------+--------+-------------+----------------
A | 100 | 0 | 0
B | 200 | 100 | 100
C | 300 | 200 | 200
D | | 300 | 300
E | | | 300
F | | | 300
(6 rows)
我更新了@klin 的回答。下面的函数允许传递任何元素,具有偏移量和默认参数。
滞后(表达式[,偏移量[,默认值]])
create or replace function swf_lag_trans(anyarray, anyelement, integer,
anyelement)
returns anyarray language plpgsql as $$
begin
if is null then
:= array_fill(, array[+1]);
end if;
if [+1] is not null then
for i in 1.. loop
[i]:= [i+1];
i := i+1;
end loop;
[+1]:= ;
end if;
return ;
end $$;
create or replace function swf_lag_final(anyarray)
returns anyelement language sql as $$
select [1];
$$;
create aggregate swf_lag(anyelement, integer, anyelement) (
sfunc = swf_lag_trans,
stype = anyarray,
finalfunc = swf_lag_final
);
和用法:
with my_table(name, salary) as (
values
('A', 100),
('B', 200),
('C', 300),
('D', null),
('E', null),
('F', null)
)
select
name, salary,
lag(salary, 2, 123) over (order by salary) prev_salary,
swf_lag(salary, 2, 123) over (order by salary) my_prev_salary
from my_table;
对我有用。
如果需要,请更正。
左侧面板数据没有 IGNORE NULLS。
在右侧面板数据上使用 IGNORE NULLS.
所以我需要在 PostgreSQL 中获得正确的变体
需要在 PostgreSQL 的 window 函数(LEAD 和 LAG)中模拟 Oracle IGNORE NULLS。
SELECT empno,
ename,
orig_salary,
LAG(orig_salary, 1, 0) IGNORE NULLS OVER (ORDER BY orig_salary) AS sal_prev
FROM tbl_lead;
如果有NULL,应该return最新的非空值。
我已经通过 PostgreSQL 用户定义的聚合函数尝试过,但是很难理解它的方法https://www.postgresql.org/docs/9.6/static/sql-createaggregate.html
解决方案不能通过WITH子句或子查询来实现,因为它用于复杂查询。
聚合有点复杂,因为你必须存储两个以前的值。可以使用数组作为 state-data
和最终函数来完成:
create or replace function my_lag_trans_fun(numeric[], numeric)
returns numeric[] language plpgsql as $$
begin
if [2] is not null then
[1]:= [2];
[2]:= ;
end if;
return ;
end $$;
create or replace function my_lag_final_fun(numeric[])
returns numeric language sql as $$
select [1];
$$;
create aggregate my_lag(numeric) (
sfunc = my_lag_trans_fun,
stype = numeric[],
initcond = '{0,0}',
finalfunc = my_lag_final_fun
);
用法:
with my_table(name, salary) as (
values
('A', 100),
('B', 200),
('C', 300),
('D', null),
('E', null),
('F', null)
)
select
name, salary,
lag(salary, 1, 0) over (order by salary) prev_salary,
my_lag(salary) over (order by salary) my_prev_salary
from my_table;
name | salary | prev_salary | my_prev_salary
------+--------+-------------+----------------
A | 100 | 0 | 0
B | 200 | 100 | 100
C | 300 | 200 | 200
D | | 300 | 300
E | | | 300
F | | | 300
(6 rows)
我更新了@klin 的回答。下面的函数允许传递任何元素,具有偏移量和默认参数。
滞后(表达式[,偏移量[,默认值]])
create or replace function swf_lag_trans(anyarray, anyelement, integer,
anyelement)
returns anyarray language plpgsql as $$
begin
if is null then
:= array_fill(, array[+1]);
end if;
if [+1] is not null then
for i in 1.. loop
[i]:= [i+1];
i := i+1;
end loop;
[+1]:= ;
end if;
return ;
end $$;
create or replace function swf_lag_final(anyarray)
returns anyelement language sql as $$
select [1];
$$;
create aggregate swf_lag(anyelement, integer, anyelement) (
sfunc = swf_lag_trans,
stype = anyarray,
finalfunc = swf_lag_final
);
和用法:
with my_table(name, salary) as (
values
('A', 100),
('B', 200),
('C', 300),
('D', null),
('E', null),
('F', null)
)
select
name, salary,
lag(salary, 2, 123) over (order by salary) prev_salary,
swf_lag(salary, 2, 123) over (order by salary) my_prev_salary
from my_table;
对我有用。 如果需要,请更正。