Oracle SQL порядок в проблемах подзапроса!
Я пытаюсь запустить подзапрос в 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
Ответы
Ответ 1
Фактически "заказ" имеет смысл только в самом внешнем запросе - если вы заказываете в подзапросе, внешнему запросу разрешается скремблировать результаты по желанию, поэтому порядок подзапросов практически не имеет значения.
Похоже, вы просто хотите получить минимум 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>
Ответ 2
Оба dcw и Dems предоставили соответствующие альтернативные запросы. Я просто хотел подбросить объяснение, почему ваш запрос не ведет себя так, как вы ожидали.
Если у вас есть запрос, включающий ROWNUM и ORDER BY, Oracle сначала применяет ROWNUM, а затем ORDER BY. Таким образом, запрос
SELECT *
FROM emp
WHERE rownum <= 5
ORDER BY empno
получает произвольные 5 строк из таблицы EMP
и сортирует их - почти наверняка не то, что предназначалось. Если вы хотите получить строки "first N", используя ROWNUM, вам нужно будет вложить запрос. Этот запрос
SELECT *
FROM (SELECT *
FROM emp
ORDER BY empno)
WHERE rownum <= 5
сортирует строки в таблице EMP и возвращает первые 5.
Ответ 3
Я испытал это сам, и вам нужно использовать 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
Ответ 4
Подтвержденный ответ прост.
Рассмотрим подзапрос, который генерирует уникальный номер индекса строки.
Например 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
будет охватывать большинство модулей БД.
Но все же, если у вас нет одного из этих параметров, например, ROWNUM
- это ваш единственный вариант, тогда ORDER BY
в подзапросе обязательно!