Search code examples
sqlpostgresqlt-sqlouter-apply

Postgre equivalent of MSSQL outer apply


The below code works fine with MSSQL. Any suggestion on how to translate this to Postgre?

;with mySource  as (
  SELECT 1050
LineID, 1 SeqNo, NULL Val
UNION SELECT 1050 LineID, 2
SeqNo, NULL Val
UNION SELECT 1050 LineID, 3
SeqNo, 'ABC' Val
UNION SELECT 1050 LineID, 4
SeqNo, NULL Val
UNION SELECT 1050 LineID, 5
SeqNo, NULL Val
UNION SELECT 1050 LineID, 6
SeqNo, 'CDE' Val
UNION SELECT 1050 LineID, 7
SeqNo, NULL Val
UNION SELECT 1050 LineID, 8
SeqNo, NULL Val
UNION SELECT 1050 LineID, 9
SeqNo, 'EFG' Val
UNION SELECT 1050 LineID, 10
SeqNo, NULL Val
UNION SELECT 2222 LineID, 1
SeqNo, NULL Val
UNION SELECT 2222 LineID, 2
SeqNo, 'ABC' Val
UNION SELECT 2222 LineID, 3
SeqNo, 'CDE' Val
UNION SELECT 2222 LineID, 4
SeqNo, NULL Val
UNION SELECT 2222 LineID, 5
SeqNo, NULL Val
UNION SELECT 2222 LineID, 6
SeqNo, 'EFG' Val
UNION SELECT 2222 LineID, 7
SeqNo, NULL Val
UNION SELECT 2222 LineID, 8
SeqNo, 'HIJ' Val
UNION SELECT 2222 LineID, 9
SeqNo, NULL Val
UNION SELECT 2222 LineID, 10
SeqNo, 'KLM' Val
) 
Select LineID,SeqNo, Coalesce(bu,ba) Val 
from mySource m
outer apply (select top 1 Val 
from mySource m1 
WHERE m1.LineID=m.LineID and m1.SeqNo<=m.SeqNo and Val is not null 
Order by SeqNo DESC) d1(bu) 
outer APPLY (SELECT TOP 1 Val 
FROM mySource m3 
WHERE  m3.LineID=m.LineID and m3.SeqNo>= m.SeqNo AND Val IS NOT NULL 
ORDER  BY SeqNo) d3(ba)
ORDER BY m.LineID, m.SeqNo

Solution

  • The equivalent for outer apply in Posgres would be left join lateral. You also need to replace TOP 1, which is T-SQL specific, with LIMIT.

    It is also possible to shorten the common table expression to use the values() syntax.

    with mySource(LineID, SeqNo, Val)  as (values
        (1050, 1, null),
        (1050, 2, null),
        (1050, 3, null),
        ...
        (2222, 10, 'KLM')
    )
    select LineID, SeqNo, Coalesce(bu,ba) Val 
    from mySource m
    left join lateral (
        select Val bu 
        from mySource m1 
        where m1.LineID = m.LineID and m1.SeqNo <= m.SeqNo and Val is not null 
        order by SeqNo desc
        limit 1
    ) d1 on true 
    left join lateral (
        select Val ba
        from mySource m3 
        where m3.LineID = m.LineID and m3.SeqNo >= m.SeqNo AND Val is not null 
        order  by SeqNo
        limit 1
    ) d3 on true
    order by m.LineID, m.SeqNo
    

    Looking at the query, I tend to suspect that its logic could be largely simplified with window functions (lag() and lead() come to mind). You might want to ask another question with more details on what you are trying to accomplish, along with sample data and expected results.