我在Postgres有一张表,如下所示:
# select * from p;
id | value
----+-------
1 | 100
2 |
3 |
4 |
5 |
6 |
7 |
8 | 200
9 |
(9 rows)
Run Code Online (Sandbox Code Playgroud)
我想查询使它看起来像这样:
# select * from p;
id | value | new_value
----+-------+----------
1 | 100 |
2 | | 100
3 | | 100
4 | | 100
5 | | 100
6 | | 100
7 | | 100
8 | 200 | 100
9 | | 200
(9 rows)
Run Code Online (Sandbox Code Playgroud)
我已经可以在select中使用子查询执行此操作,但在我的实际数据中,我有20k或更多行,并且它变得非常慢.
这可以在窗口函数中做到吗?我喜欢使用lag(),但它似乎不支持IGNORE NULLS选项.
select id, value, lag(value, 1) over (order by id) as new_value from p;
id | value | new_value
----+-------+-----------
1 | 100 |
2 | | 100
3 | |
4 | |
5 | |
6 | |
7 | |
8 | 200 |
9 | | 200
(9 rows)
Run Code Online (Sandbox Code Playgroud)
ada*_*mar 74
我发现SQL Server的这个答案也适用于Postgres.从来没有做过,我认为这种技术非常聪明.基本上,他通过在嵌套查询中使用case语句为窗口函数创建自定义分区,该嵌套查询在值不为空时递增总和,否则单独留下它.这允许人们用与前一个非空值相同的数字来描述每个空部分.这是查询:
SELECT
id, value, value_partition, first_value(value) over (partition by value_partition order by id)
FROM (
SELECT
id,
value,
sum(case when value is null then 0 else 1 end) over (order by id) as value_partition
FROM p
ORDER BY id ASC
) as q
Run Code Online (Sandbox Code Playgroud)
结果如下:
id | value | value_partition | first_value
----+-------+-----------------+-------------
1 | 100 | 1 | 100
2 | | 1 | 100
3 | | 1 | 100
4 | | 1 | 100
5 | | 1 | 100
6 | | 1 | 100
7 | | 1 | 100
8 | 200 | 2 | 200
9 | | 2 | 200
(9 rows)
Run Code Online (Sandbox Code Playgroud)
您可以在Postgres中创建自定义聚合函数。这是该int类型的示例:
CREATE FUNCTION coalesce_agg_sfunc(state int, value int) RETURNS int AS
$$
SELECT coalesce(value, state);
$$ LANGUAGE SQL;
CREATE AGGREGATE coalesce_agg(int) (
SFUNC = coalesce_agg_sfunc,
STYPE = int);
Run Code Online (Sandbox Code Playgroud)
然后照常查询。
SELECT *, coalesce_agg(b) over w, sum(b) over w FROM y
WINDOW w AS (ORDER BY a);
a b coalesce_agg sum
- - ------------ ---
a 0 0 0
b ? 0 0
c 2 2 2
d 3 3 5
e ? 3 5
f 5 5 10
(6 rows)
Run Code Online (Sandbox Code Playgroud)
好吧,我不能保证这是最有效的方法,但有效:
SELECT id, value, (
SELECT p2.value
FROM p p2
WHERE p2.value IS NOT NULL AND p2.id <= p1.id
ORDER BY p2.id DESC
LIMIT 1
) AS new_value
FROM p p1 ORDER BY id;
Run Code Online (Sandbox Code Playgroud)
以下索引可以改进大型数据集的子查询:
CREATE INDEX idx_p_idvalue_nonnull ON p (id, value) WHERE value IS NOT NULL;
Run Code Online (Sandbox Code Playgroud)
假设value稀疏(例如有很多空值)它将运行良好。
| 归档时间: |
|
| 查看次数: |
18980 次 |
| 最近记录: |