【发布时间】:2015-04-25 06:19:46
【问题描述】:
我希望将此使用交叉应用的 SQL Server (T-SQL) 查询转换为 Oracle 11g。 Oracle 直到 12g 才支持 Cross Apply,所以我必须找到解决方法。查询背后的想法是对于 = 'Foobar' 的每个 Tab.Name,我需要找到具有相同 ID 的前一行的名称,该 ID 由 Tab.Date 排序。 (此表包含 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 语句将它们过滤掉。该表有数百万条记录,因此对每个 ID 这样做是不可行的。基本上,我想更改子查询中的操作顺序,只为单个 ID 拉回行,对这些行进行排序以找到前一个,然后加入。关于如何调整它的任何想法?
TL;DR SQL Server: 过滤器、订单、连接 Oracle:订单、过滤器、连接
【问题讨论】:
-
你的内部查询是
t1.Date = t2.Date,然后是order by t2.Date。所以本质上它是在选择一个随机的行。 -
@Andomar 这听起来很有趣,你能详细说明为什么会这样吗?
-
@Wjdavis5: 好吧,如果你首先要求所有日期都等于某个值(比如
t1.Date),然后按该值排序,那么排序不会有太大作用。 -
@Andomar 感谢您指出这一点,它不应该在 t1.Date = t2.Date 上进行过滤。我现在已经更新了查询。
-
MS SQL Server 的
APPLY在 Oracle 中变为LATERAL。但是,我不确定引入了什么修订版。我相信,在最新版本中,Oracle 也确实支持APPLY。
标签: sql-server oracle11g cross-apply