2015-02-23 2 views
4

Я ищу, чтобы преобразовать этот запрос SQL Server (T-SQL), который использует крест, применяется к Oracle 11g. Oracle не поддерживает Cross Apply до 12g, поэтому мне нужно найти работу. Идея запроса - для каждого Tab.Name, что = 'Foobar', мне нужно найти имя предыдущей строки с тем же идентификатором, который был указан Tab.Date. (Эта таблица содержит несколько строк для 1 идентификатора с разными именами и датами).Преобразование T-SQL Cross Применить к Oracle

Вот код 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') 

Технически, я смог воссоздать этот же функциональность в Oracle с помощью LEFT JOIN и функции LAG():

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 невозможно. В принципе, я хочу изменить порядок операций в подзапросе, чтобы просто отбросить строки для одного идентификатора, отсортировать эти строки, чтобы найти предыдущий, и присоединиться к этому. Любые идеи о том, как настроить его?

TL; DR SQL Server: фильтров, заказы, присоединяется Oracle: заказов, фильтры, присоединяется

+1

Ваш внутренний запрос говорит 't1.Date = t2.Date', а затем' order by t2.Date'. Таким образом, он выбирает случайную строку. – Andomar

+0

@Andomar Это звучит интересно, не могли бы вы рассказать о том, почему это так? – Wjdavis5

+0

@ Wjdavis5: ну, если вы сначала требуете, чтобы все даты были равны определенному значению (например, 't1.Date'), а затем отсортируйте по этому значению, сортировка не будет делать многое. – Andomar

ответ

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 
+0

Не совсем верно. Я хочу получить предыдущую строку (упорядоченную по дате) для Name = 'Foobar'. Имя может иметь любую дату, поэтому это не обязательно самая ранняя строка для идентификатора. – Brett