Запрос со смещением возвращает перекрывающиеся наборы данных

#mysql #sql #oracle #offset #sql-limit

#mysql #sql #Oracle #смещение #sql-limit

Вопрос:

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

Я ожидал, что следующее даст мне два уникальных набора результатов. 1-100, а затем 101-200 результатов, которые были бы возвращены, если бы для первой строки было установлено ограничение в 200.

 select  * from "APPR" /*  index(APPR APPR_IDX01) */ where  ("APPROVER" = 'A') or  ("APPROVER" > 'A') order by "APPROVER"  fetch first 100 rows only ;

select  * from "APPR" /*  index(APPR APPR_IDX01) */ where  ("APPROVER" = 'A') or  ("APPROVER" > 'A') order by "APPROVER" offset 100 rows fetch next 100 rows only ;
  

Итак, если для утверждающего A есть 150 элементов, первые результаты должны быть:

  • A, item1
  • ….
  • A, item100

Последующий вызов (смещение на 100), дающий

  • A, item101
  • A, item150
  • B, item1
  • B, item2
  • ….
  • B, item201

К сожалению, второй набор содержит некоторые записи из первой партии значений. Вероятно, действительно глупая ошибка, но я не могу найти объяснение, почему это должно произойти.

—- Обновлено в результате комментариев Первичный ключ состоит из Утверждающего и нескольких других полей, которые вместе образуют составной и уникальный первичный ключ.

Код будет вызываться через ODBC и будет использоваться на серверной части Oracle и MySQL.

Комментарии:

1. Каков первичный ключ вашей таблицы?

2. Первичный ключ состоит из «утверждающего» и нескольких других столбцов, идентифицирующих утверждаемый элемент.

Ответ №1:

В Oracle, если вы делаете «order by» для столбца, содержащего одинаковые значения (например, у вас есть — ‘A’, ‘A’, ‘A’ …), порядок записей внутри значений ‘A’ будет случайным.

Пожалуйста, попробуйте изменить ваши запросы на … order by "APPROVER", rowid

Комментарии:

1. Random, о, предполагал, что будет некоторый «естественный» порядок, который будет сохраняться между запросами. Решение, впервые разработанное в Oracle, должно вызываться через интерфейс ODBC и также должно работать на MySQL.

2. Добавлен столбец с уникальным автоматически увеличивающимся числом, поэтому решение является универсальным для Oracle и MySQL, а также комментарии от @GMB это обеспечивает решение

Ответ №2:

Предположительно, APPROVER это не уникальный столбец. Поскольку могут быть дубликаты, order by клаус нестабилен, и предложение offset может генерировать дубликаты.

Простое решение — добавить больше столбцов order by , чтобы разорвать связи. Предполагая, что (approver, item) это уникальный набор столбцов, это будет:

 select  * 
from appr
where approver = 'A' or approver > 'A'
order by approver, item
fetch first 100 rows only
-- then: offset 100 rows fetch next 100 rows only
  

Примечания:

  • нет необходимости заключать идентификаторы с заглавными буквами (имена таблиц или столбцов) в двойные кавычки: это уже используется по умолчанию в Oracle

  • круглые скобки вокруг or условий в этом простом случае излишни

  • если approver всегда имеет длину в один символ, то where предложение можно упростить следующим образом where approver >= 'A'

  • используйте подсказки по индексу, только если вы действительно знаете, зачем вы это делаете (я не говорю, что вы этого не делаете, но я удалил его на всякий случай); в большинстве случаев база данных знает лучше

Комментарии:

1. Правильный «УТВЕРЖДАЮЩИЙ» не является уникальным. Первоначальные тесты не показали дубликатов, но при увеличении масштаба они появились. Что касается круглых скобок, то они включаются только в том случае, если код формирует набор запросов по аналогичному шаблону, некоторые из которых полагаются на скобки для обеспечения приоритета. Утверждающий — это только один символ, чтобы упростить вопрос. Отмеченные в указателе подсказки — они были добавлены только после изучения и хронометража Поясняющих планов.