Выберите ближайший, но не больше строки - PullRequest
2 голосов
/ 26 марта 2012

Учитывая табличное действие (начало: ДАТА, длина: НОМЕР, тип: НОМЕР), со всеми уникальными записями, мне нужно выбрать (например, длину последнего действия с типом Y перед временем X:

select action.length 
 where action.type = Y 
   and action.start is the biggest, but not greater than X

Предлагаемое решение (улучшено):

  with actionView as (select * from action where type = Y and time <= X) 
select length
  from actionView
 where time = (select max(time) from actionView)

Но это все еще включает два выбора.

Что я хотел бы спросить: возможно ли выполнить какой-либо аналитический, иерархический или любой другой оракул-магии для этого запроса, чтобы улучшить его?

(Возможно, мне нужно что-то вроде этого алгоритма, но я не знаю, как выразить это в SQL:

savedAction.time = MinimalTime
foreach action in actions
  if action.type = y and savedAction.time < action.time <= X
    savedAction = action
return savedAction;

)

Ответы [ 3 ]

3 голосов
/ 26 марта 2012

В Oracle нет предложения LIMIT (PostgreSQL, MySQL) или TOP (SQL Server), как в других СУБД. Но вы можете использовать ROWNUM для этого:

SELECT *
FROM  (
    SELECT length 
    FROM   action
    WHERE  type = Y 
    AND    start < X
    ORDER  BY start DESC
    )
WHERE rownum = 1;

Таким образом, таблица будет запрашиваться только один раз.
Подробности в руководстве .


В ответ на комментарий Dems я цитирую по ссылке выше:

Если вы встраиваете предложение ORDER BY в подзапрос и помещаете ROWNUM условие в запросе верхнего уровня, то вы можете заставить ROWNUM условие, которое будет применено после упорядочения строк.

2 голосов
/ 26 марта 2012

Вы можете использовать ROW_NUMBER (), чтобы оценить это за одно сканирование ...

WITH
  sequenced_data
AS
(
  SELECT
    ROW_NUMBER() OVER (PARTITION BY x ORDER BY start DESC) AS sequence_id,
    *
  FROM
    action
  WHERE
    type = Y
    AND start < Z
)
SELECT
  *
FROM
  sequenced_data
WHERE
  sequence_id = 1

Вам не нужен PARTITION BY, но он используется там, где вы получаете строку 'max' на группу (например, на человека или элемент в вашей базе данных).

0 голосов
/ 26 марта 2012

Я не знаю ни о какой магии, но:

  with (select length, time from action where type = Y and time <= X) as typed_action
  select length from typed_action
  where time = (select max(time) from typed_action)

Даст вам меньше предложений "где" для выполнения и (намного?) Меньшую временную таблицу typed_action.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...