Search code examples
sqloracleplsqlwindow-functions

Window functions (lead/lag) with collections in Oracle SQL (PL/SQL)


I want to port a SQL script which exists in PostgreSQL to Oracle SQL. Here is sample data:

NR                      GRD DT
00000000000000000001    06  01.01.13
00000000000000000001    06  01.01.13
00000000000000000001    21  01.01.13
00000000000000000002    06  01.01.13
00000000000000000002    21  01.01.13
00000000000000000004    01  31.03.13

Here is my simplified code:

CREATE TYPE tbl_array AS TABLE OF NVARCHAR2(4000);

with prep as (
Select
    nr
    , cast(collect(grd) as tbl_array) grds
from
    test_table
group by
    nr                    
)
select 
    prep.*
    , lead(grds) over (order by nr) as lead_grds
from 
    prep

But the window function does not work. I get the following error message:

ORA-00932: inconsistent datatypes: expected - got ORACLEANALYTICS.TBL_ARRAY

Is it because of the created type? How can I solve this issue? In step two I want to check the intersection of the collections with others (already working) so I need them. Is this somehow possible?

Cheers Chris


Solution

  • You could use ROW_NUMBER() to simulate LAG/LEAD:

    with prep as (
      select
        nr, CAST(collect(grd) AS tbl_array) grds,ROW_NUMBER() OVER(ORDER BY nr) AS rn
      from tab
      group by nr                    
    )
    select p.nr, p.grds, p2.grds AS lead_grds
        --, lead(grds) over (order by nr) as lead_grds
    from prep p
    LEFT JOIN prep p2
      ON p2.rn = p.rn +1;
    

    Output from prep:

    ┌──────────────────────┬────────────────────────────────┬────┐
    │          NR          │              GRDS              │ RN │
    ├──────────────────────┼────────────────────────────────┼────┤
    │ 00000000000000000001 │ HR.TBL_ARRAY('06', '21', '06') │  1 │
    │ 00000000000000000002 │ HR.TBL_ARRAY('06', '21')       │  2 │
    │ 00000000000000000004 │ HR.TBL_ARRAY('01')             │  3 │
    └──────────────────────┴────────────────────────────────┴────┘
    

    Output of entire query:

    ┌──────────────────────┬──────────────────────────────┬──────────────────────────┐
    │          NR          │             GRDS             │        LEAD_GRDS         │
    ├──────────────────────┼──────────────────────────────┼──────────────────────────┤
    │ 00000000000000000001 │HR.TBL_ARRAY('06', '21', '06')│ HR.TBL_ARRAY('06', '21') │
    │ 00000000000000000002 │HR.TBL_ARRAY('06', '21')      │ HR.TBL_ARRAY('01')       │
    │ 00000000000000000004 │HR.TBL_ARRAY('01')            │                          │
    └──────────────────────┴──────────────────────────────┴──────────────────────────┘
    

    Equivalent in PostgreSQL:

    WITH prep AS (
      SELECT NR, ARRAY_AGG(GRD) AS grds
      FROM tab
      GROUP BY NR
    )
    SELECT prep.*, LEAD(grds) OVER(ORDER BY nr) AS lead_grds
    FROM prep;
    

    DBFiddle Demo