如何找到两列分组的cloumn的prev值?

时间:2019-07-01 09:38:11

标签: sql postgresql

我要从下表中找到按fname和lname分组的新代码和上一个代码。

fname | lname | code |
----------------------
jack  | jonas | 987  |  
nick  | fun   | 563  |  
jack  | jonas | 674  |
jack  | jonas | 672  |

输出表:

fname | lname | new_code | prev_code |
-------------------------------------
jack  | jonas | 987      | 674

PS:我的情况不支持“ 与众不同”。我猜可以使用左连接或数据透视。

4 个答案:

答案 0 :(得分:1)

使用row_number() widown功能,如下尝试

with cte as
(
select *,
row_number() over(partition by fname,lname order by date desc) rn
from table_name
), cte1 as
(
select * from cte where rn<=2
), select fname,lname,
max(case when rn=1 then code end) as code,
max(case when rn=2 then code end) as prevcode fron cte1
group by fname,lnamae

答案 1 :(得分:1)

step-by-step demo:db<>fiddle

SELECT
    *
FROM (
    SELECT DISTINCT ON (fname, lname)
        *,
        lead(code) OVER (PARTITION BY fname, lname ORDER BY my_date DESC) as prev
    FROM
        my_table
    ORDER BY 
        fname, lname, my_date DESC
) s
WHERE prev IS NOT NULL
  1. lead() window function提供了先前的代码
  2. DISTINCT ON过滤每个组的第一个数据集
  3. 如果没有以前的代码,则可以使用WHERE子句对其进行过滤

答案 2 :(得分:1)

您可以使用窗口函数first_value,nth_value例如

select
distinct on (fname, lname)
first_value(fname ) over (PARTITION by fname, lname order by some_date desc RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
first_value(lname ) over (PARTITION by fname, lname order by some_date desc RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
nth_value(code,1) over (PARTITION by fname, lname order by some_date desc RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
nth_value(code,2) over (PARTITION by fname, lname order by some_date desc RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
from public.tbl_test

答案 3 :(得分:1)

在Postgres中,您可以使用distinct onlag()获得每个名称的最新对:

select distinct on (lname, fname) t.*
from (select t.*,
             lag(code) over (partition by lname, fname order by datecol) as prev_code
      from t
     ) t
where prev_code is not null
order by lname, fname, date desc;

您也可以在不使用子查询的情况下执行此操作:

select distinct lname, fname,
       first_value(code) over (partition by lname, fname order by datecol desc),
       nth_value(code, 2) over (partition by lname, fname order by datecol desc)
from t;

但是,当第二个代码在那里时,您仍然需要一个子查询来过滤值。

或者,您可以使用数组:

select lname, fname,
       (array_agg(code order by datecol desc))[1] as code,
       (array_agg(code order by datecol desc))[2] as prev_code
from t
group by lname, fname
having count(*) >= 2;