SQL: выберите "до"

Я ищу способ выбора, пока сумма не будет достигнута.

Моя таблица "документы" имеет "tag_id" а также "sizeполя

Я хочу выбрать все документы с tag_id = 26 но я знаю, что могу выдержать только 600 единиц размера. Таким образом, нет смысла отбирать 100 документов и отбрасывать 90 из них, когда я мог знать, что первые 10 уже добавили до> 600 единиц.

Итак, цель состоит в том, чтобы не возвращать тонну данных для анализа, когда я собираюсь отбросить большую их часть.

... но я бы также хотел не использовать в этом приложении работу с курсорами.

Я использую MySQL.

3 ответа

Решение

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

SELECT d.id, d.size, d.date_created
FROM documents d
INNER JOIN documents d2 ON d2.tag_id=d.tag_id AND d2.date_created >= d.date_created
WHERE d.tag_id=26
GROUP BY d.id, d.size, d.date_created
HAVING sum(d2.size) <= 600
ORDER BY d.date_created DESC

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

  • Он останавливается на <= 600, поэтому в большинстве случаев вы не будете точно заполнять свой размер. Это означает, что вы можете настроить его, чтобы разрешить еще одну запись. Например, если первая запись> 600, запрос ничего не даст, и это может быть проблемой.
  • В дальнейшем он ничего не сделает для проверки дополнительных записей меньшего размера, которые все еще могут поместиться под заглушкой.
  • Записи с одинаковыми значениями date_created могут быть "двойным счетом" здесь и там.

редактировать
Обновлено, так как он добавил информацию, которую он сортирует по дате.

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

 declare @documents_temp table (
    tag_id int,
    size int,
    cumulative_size int null)

insert into @documents_temp
select tag_id, size, size from documents order by tag_id

update @documents_temp d set d.cumulative_size = d.size + 
    (select top 1 cumulative_size from @documents_temp 
     where tag_id < d.tag_id order by tag_id desc)

select tag_id, size from @documents_temp where cumulative_size <= 600

Не знаю, стоит ли это того.

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

select a.id, (select sum(b.size) from documents b where b.id <= a.id and b.tag_id = 26)
from documents a
where a.tag_id = 26
order by a.id

Кроме того, это было сделано в pgsql, поэтому я не уверен, что этот точный синтаксис будет работать в MySQL.

Затем вы можете обернуть это в другой запрос, который ищет те, у которых сумма> 600 (вам нужно будет назвать столбец суммы) и взять первый идентификатор. Затем обработайте все идентификаторы ниже, включая этот.

Другие вопросы по тегам