簡體   English   中英

如何使用 first_value window function 獲取 Postgresql 中的最后一個非 null 值

[英]How to use first_value window function to get last non null value in Postgresql

我想在 PgSQL 中執行填充活動

動態鏈接庫:

create table brands 
(
id int,
category varchar(20),
brand_name varchar(20)
);
insert into brands values
(1,'chocolates','5-star')
,(2,null,'dairy milk')
,(3,null,'perk')
,(4,null,'eclair')
,(5,'Biscuits','britannia')
,(6,null,'good day')
,(7,null,'boost')
,(8,'shampoo','h&s')
,(9,null,'dove');

預計 output 是:

類別 品牌
巧克力 5星級
巧克力 牛奶
巧克力 津貼
巧克力 泡芙
餅干 大不列顛
餅干 再會
餅干 促進
洗發水 健康與安全
洗發水 鴿子

我嘗試使用以下腳本,但它似乎不起作用。

select id,
      first_value(category)
      over(order by case when category is not null then id end desc nulls last) as category,
      brand_name
from brands

有人可以建議修復。

在 MS SQL 中,以下代碼片段似乎工作正常。

select id,
       first_value (category) IGNORE NULLS
       over(order by id desc
        rows between current row and unbounded following) as category,
       brand_name
FROM brands
ORDER BY id
with cte as (
select id,
       category,
       count(category) over (order by id) as category_id,
       brand_name
  from brands)
select id,
       first_value(category) over (partition by category_id order by id) as category,
       brand_name
  from cte;

更新:為每個請求添加了沒有 CTE 的查詢:

select id,
       (array_agg(category) over (order by id))[max(case when category is null then 0 else id end) over (order by id)] as category,
       brand_name
  from brands;

我認為使用CTE沒有任何問題(請參閱 JHH 的回答),我更願意這樣做。

Postgres DB 不提供 SQLServer DB 的IGNORE NULLS概念,所以我想你應該停止認為你會得到一個幾乎相同的 Postgres DB 查詢,就像在 MS SQL 中一樣。

無論如何,如果您不想使用 CTE 或復雜的子查詢,您可以定義自己的 function 和聚合並運行它。

Function 創作:

-- CREATE your function
CREATE FUNCTION yourFunction(STATE anyelement, VALUE anyelement)
    RETURNS anyelement
    IMMUTABLE PARALLEL safe
AS
$$
SELECT COALESCE(VALUE, STATE); -- Replace NULL values here
$$ LANGUAGE SQL;

使用 function 聚合創建:

-- CREATE your aggregate
CREATE AGGREGATE yourAggregate(ANYELEMENT) (
    sfunc = yourFunction, -- Call your function here
    stype = ANYELEMENT
);

您使用此聚合的查詢:

SELECT id, 
  yourAggregate(category) -- Call your aggregate here
  OVER (ORDER BY id, category), 
  brand_name
FROM brands
ORDER BY id;

當然,您應該將 function 和聚合都重命名並使用更有意義的名稱。

這將產生與 CTE 版本相同的結果。

嘗試: db<>fiddle

如果您熱衷於定義和使用自己的功能並且您會經常使用它,那么您可以這樣做。

否則,只需使用 CTE,就可以了。 沒有理由不使用 CTE。

請始終注意,在使用自己的函數時,您面臨性能不佳的風險,因此您應該檢查此查詢是否太慢。

恐怕這在 Postgres 中沒有實現(至少在 Postgres 15 之前)。 關於 window 函數的手冊

SQL 標准為leadlagfirst_valuelast_valuenth_value定義了RESPECT NULLSIGNORE NULLS選項。 這在 PostgreSQL 中沒有實現:行為始終與標准的默認值相同,即RESPECT NULLS

因此,您必須使用 CTE 的變通方法或像 JHH 建議的子查詢,或者滾動您自己的 window function(這將相對較慢)。

請參閱(對 dba.SE 上類似問題的回答):

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM