Как найти * положение * отдельной записи в ограниченном, произвольно упорядоченном наборе записей? - PullRequest
5 голосов
/ 23 марта 2009

MySQL

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

В качестве примера можно привести фотогалерею. Вы попадаете на одну фотографию, но система должна знать, каково ее смещение во всей галерее.

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

Ответы [ 7 ]

2 голосов
/ 23 марта 2009

Итак, сначала вы создаете виртуальную таблицу с позицией #, упорядоченной в соответствии с тем, какой у вас ORDER BY, затем вы выбираете самую высокую из этого набора. Это позиция в большом наборе результатов. Вы можете столкнуться с проблемами, если не упорядочите по уникальному значению / набору значений ...

Если вы создаете индекс для (photo_gallery_id, date_created_on), он может выполнить сканирование индекса (в зависимости от распределения фотографий), которое должно быть быстрее сканирования таблицы (если ваш gallery_id не составляет 90% фотографий или еще много чего).

SELECT @row := 0; 
SELECT MAX( position ) 
  FROM ( SELECT @row := @row + 1 AS position
           FROM photos
          WHERE photo_gallery_id = 43
            AND date_created_on <= 'the-date-time-your-photo-was' 
          ORDER BY date_created_on ) positions;
0 голосов
/ 27 сентября 2010

Нет необходимости в дополнительной таблице, почему бы просто не подсчитать записи?

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

Вы также знаете идентификатор текущей записи; скажем, он заказан на дату:

Смещение записи - это общее количество записей, подсчитанных с датой <этой даты. </p>

SELECT COUNT(1) FROM ... WHERE date < "the-date"

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

0 голосов
/ 23 марта 2009

Вы должны понимать разницу между «ключом приложения» и «техническим ключом».

Технический ключ существует с единственной целью сделать предмет уникальным. Обычно он генерируется в INTEGER или BIGINT (идентичность, что угодно). Этот ключ используется для поиска объектов в базе данных, быстрого определения того, что объект уже сохранен (идентификаторы должны быть> 0, поэтому объект с идентификатором по умолчанию == 0 еще не находится в БД) и т. Д.

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

Подумайте упорядоченный список: это значение по умолчанию в большинстве языков. У вас есть набор элементов, доступ к которым осуществляется по индексу. Для базы данных этот индекс является ключом приложения, поскольку наборы в базе данных неупорядочены (или, скорее, база данных не гарантирует какого-либо упорядочения, если вы не укажете ORDER BY). По той же причине пролистывание результатов запроса является такой болью: базам данных действительно не нравится идея «позиции».

Итак, что вы должны сделать, это добавить строку индекса (т. Е. INTEGER, который говорит, в какой позиции в галерее находится ваше изображение; не индекс базы данных для более быстрого доступа, даже если вы должны создать индекс для этого столбца ... ) и поддерживать это. Для каждой вставки необходимо UPDATE index = index + 1 where index >= insertion_point и т. Д.

Да, это отстой. Единственное известное мне решение: используйте платформу ORM, которая решит это за вас.

0 голосов
/ 23 марта 2009

Если предположить, что позиция определяется только идентификатором, разве это не так просто, как подсчет всех записей с меньшим значением идентификатора?:

select
    po.[id]
    ...
    ((select count(pi.[id]) from photos pi where pi.[id] < po.[id]) + 1) as index
    ...
from photos po
...

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

0 голосов
/ 23 марта 2009

Вы не говорите, какую СУБД вы используете, и «решение» будет меняться соответственно. В Oracle вы могли бы сделать это (но я бы вас не рекомендовал!):

select photo, offset
from
( select photo
  ,      row_number() over (partition by gallery_id, order by photo_seq) as offset
  from   photos
)
where  id = 123

В этом запросе будут выбраны все фотографии (полное сканирование таблицы), а затем выбрана та, которую вы просили - не производительный запрос!

Я бы предложил, если вам действительно нужно , эта информация должна храниться.

0 голосов
/ 23 марта 2009

Поскольку вы не знаете, какую базу данных вы используете, в SQL Server 2005 вы можете использовать

SELECT 
  ROW_NUMBER() OVER (ORDER BY PhotoID)
  , PhotoID
FROM dbo.Photos
0 голосов
/ 23 марта 2009

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

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