Подтвердить что ты не робот

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
4b9b3361

Ответ 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 в подзапросе обязательно!