转换T-SQL交叉应用到Oracle

时间:2015-02-23 19:44:20

标签: sql-server oracle11g cross-apply

我希望将使用交叉应用的SQL Server(T-SQL)查询转换为Oracle 11g。 Oracle在12g之前不支持Cross Apply,因此我必须找到解决方法。查询背后的想法是每个Tab.Name =' Foobar',我需要找到具有由Tab.Date排序的相同ID的前一行的名称。 (此表包含1个ID的多行,具有不同的名称和日期)。

这是T-SQL代码:

SELECT DISTINCT t1.ID
                t1.Name, 
                t1.Date, 
                t2.Date as 'PreviousDate',
                t2.Name as 'PreviousName'
FROM  Tab t1 
               OUTER apply (SELECT TOP 1 t2.Date, 
                                         t2.Name 
                            FROM  Tab t2 
                            WHERE  t1.Id = t2.Id 

                            ORDER BY t2.Date DESC) t2 
WHERE  t1.Name = 'Foobar' )

从技术上讲,我能够使用LEFT JOIN和LAG()函数在Oracle中重新创建相同的功能:

SELECT DISTINCT t1.ID
            t1.Name, 
            t1.Date, 
            t2.PreviousDate as PreviousDate,
            t2.PreviousName as PreviousName
FROM   Tab t1  
          LEFT JOIN (
                SELECT ID,
                LAG(Name) OVER (PARTITION BY ID ORDER BY PreviousDate) as PreviousName,
                LAG(Date) OVER (PARTITION BY ID ORDER BY PreviousDate) as PreviousDate
                FROM Tab) t2 ON t2.ID = t1.ID 
WHERE  t1.Name = 'Foobar' 

问题是它执行Oracle查询的顺序。它将从Tab中拉回所有行,对它们进行排序(因为LAG函数),然后它将它们连接到主查询时使用ON语句对它们进行过滤。该表有数百万条记录,因此对于EACH ID这样做是不可行的。基本上,我想更改子查询中的操作顺序,只需拉回单个ID的行,对这些行进行排序以查找前一行,然后加入。关于如何调整它的任何想法?

TL; DR SQL Server:过滤器,订单,加入 Oracle:订单,过滤器,加入

1 个答案:

答案 0 :(得分:0)

您可以使用(id)

查找每个row_number()组的最新行
select  *
from    tab t1
left join
        (
        select  row_number() over (
                    partition by id
                    order by Date desc) as rn
        ,       *
        from    t2
        ) t2
on      t1.id = t2.id
        and t2.rn = 1 -- Latest row per id