Oracle SQL упорядочить в подзапросе проблемы! - PullRequest
13 голосов
/ 25 февраля 2011

Я пытаюсь запустить подзапрос в Oracle SQL, и он не позволит мне упорядочить столбцы подзапроса.Порядок подзапроса важен, так как Oracle, похоже, по своему усмотрению выбирает, какой из возвращаемых столбцов будет возвращен в основной запрос.

select ps.id, ps.created_date, pst.last_updated, pst.from_state, pst.to_state, (select last_updated from mwcrm.process_state_transition subpst where subpst.last_updated > pst.last_updated and subpst.process_state = ps.id and rownum = 1) as next_response from mwcrm.process_state ps, mwcrm.process_state_transition pst where ps.created_date > sysdate - 1/24 and ps.id=pst.process_state order by ps.id asc

Действительно должно быть:

select ps.id, ps.created_date, pst.last_updated, pst.from_state, pst.to_state, (select last_updated from mwcrm.process_state_transition subpst where subpst.last_updated > pst.last_updated and subpst.process_state = ps.id and rownum = 1 order by subpst.last_updated asc) as next_response from mwcrm.process_state ps, mwcrm.process_state_transition pst where ps.created_date > sysdate - 1/24 and ps.id=pst.process_state order by ps.id asc

Ответы [ 4 ]

21 голосов
/ 25 февраля 2011

На самом деле «упорядочение» имеет смысл только для самого внешнего запроса - если вы заказываете в подзапросе, внешний запрос может скремблировать результаты по желанию, поэтому упорядочение подзапроса по существу ничего не делает.

ЭтоПохоже, вы просто хотите получить минимум last_updated, который больше, чем pst.last_updated - это проще, когда вы смотрите на него как на минимум (агрегат), а не на первую строку (которая вызывает другие проблемы, например, что еслидва ряда связаны для next_response?)

Дайте этому шанс.Справедливое предупреждение, прошло несколько лет с тех пор, как передо мной был Oracle, и я не привык к синтаксису подзапроса как столбца;если он взорвется, я сделаю версию с ним в предложении from.

select
    ps.id, ps.created_date, pst.last_updated, pst.from_state, pst.to_state,
    (   select min(last_updated)
        from mwcrm.process_state_transition subpst
        where subpst.last_updated > pst.last_updated
          and subpst.process_state = ps.id) as next_response
from <the rest>
16 голосов
/ 25 февраля 2011

И dcw, и Dems предоставили соответствующие альтернативные запросы. Я просто хотел объяснить, почему ваш запрос не работает так, как вы ожидали.

Если у вас есть запрос, включающий ROWNUM и ORDER BY, Oracle сначала применяет ROWNUM, а затем ORDER BY. Так что запрос

SELECT *
  FROM emp
 WHERE rownum <= 5
 ORDER BY empno

получает произвольные 5 строк из таблицы EMP и сортирует их - почти наверняка не то, что предполагалось. Если вы хотите получить «первые N» строк, используя ROWNUM, вам нужно будет вложить запрос. Этот запрос

SELECT *
  FROM (SELECT *
          FROM emp
         ORDER BY empno)
 WHERE rownum <= 5

сортирует строки в таблице EMP и возвращает первые 5.

8 голосов
/ 25 февраля 2011

Я сам испытал это, и вы должны использовать ROW_NUMBER () и дополнительный уровень подзапроса вместо rownum ...

Просто показывать новый подзапрос, что-то вроде ...

(
  SELECT
    last_updated
  FROM
  (
    select
      last_updated,
      ROW_NUMBER() OVER (ORDER BY last_updated ASC) row_id
    from
      mwcrm.process_state_transition subpst
    where
      subpst.last_updated > pst.last_updated
      and subpst.process_state = ps.id
  )
    as ordered_results
  WHERE
    row_id = 1
)
  as next_response


Альтернативой может быть использование MIN вместо ...

(
  select
    MIN(last_updated)
  from
    mwcrm.process_state_transition subpst
  where
    subpst.last_updated > pst.last_updated
    and subpst.process_state = ps.id
)
  as next_response
1 голос
/ 06 августа 2015

Подтвержденный ответ совершенно неверный. Рассмотрим подзапрос, который генерирует уникальный номер индекса строки. Например ROWNUM в Oracle.

Вам нужен подзапрос, чтобы создать уникальный номер записи для целей подкачки (см. Ниже).

Рассмотрим следующий пример запроса:

SELECT T0.*, T1.* FROM T0 LEFT JOIN T1 ON T0.Id = T1.Id
JOIN 
(
SELECT DISTINCT T0.*, ROWNUM FROM T0 LEFT JOIN T1 ON T0.Id = T1.Id
WHERE (filter...)
)
WHERE (filter...) AND (ROWNUM > 10 AND ROWNUM < 20)
ORDER BY T1.Name DESC

Внутренний запрос - это точно такой же запрос, но DISTINCT в T0. Вы не можете поместить ROWNUM во внешний запрос, поскольку LEFT JOIN (s) может генерировать гораздо больше результатов.

Если бы вы могли заказать внутренний запрос (T1.Name DESC), сгенерированный ROWNUM во внутреннем запросе совпадет. Поскольку вы не можете использовать ORDER B Y в подзапросе, числа не будут совпадать и будут бесполезны.

Слава богу, что ROW_NUMBER OVER (ORDER BY ...) исправляет эту проблему. Хотя поддерживается не всеми механизмами БД.

Один из двух методов, LIMIT (не требует ORDER) и ROW_NUMBER() OVER, будет охватывать большинство механизмов DB. Но, тем не менее, если у вас нет одного из этих параметров, например, ROWNUM - ваш единственный вариант, тогда ORDER BY в подзапросе является обязательным!

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