Архив метки: выдача

Как постранично (порционно) листать результат запроса в 1С (ака LIMIT x,y в MySQL)

Большая беда MSSQL и как следствие 1С — отсутствие возможности порционно листать записи результата запроса как в MySQL. В результате рождаются такие монстроузные алгоритмы как ниже (код не мой):

Функция GetNewsList(body, answer) Экспорт
	
	answer.error = Истина;
	answer.errortext = "Что-то пошло не так..";
	answer.result = "";
	
	Попытка
		page = ?(ЗначениеЗаполнено(body.page), Число(body.page), 1);
		Если page < 1 Тогда
			page = 1;
		КонецЕсли;
		
		nums = ?(ЗначениеЗаполнено(body.nums), Число(body.nums), 5);
		Если nums < 5 Тогда
			nums = 5;
		КонецЕсли;
		
		ПредДата = ТекущаяДата();
		ПредКод = "";
		Если page > 1 Тогда
			Запрос = Новый Запрос;
			Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 100
			               |	Хрюкости.Дата КАК Дата,
			               |	Хрюкости.Код КАК Код
			               |ПОМЕСТИТЬ тПредыдущих
			               |ИЗ
			               |	Справочник.ПоследниеСплетни КАК Хрюкости
			               |
			               |УПОРЯДОЧИТЬ ПО
			               |	Хрюкости.Дата УБЫВ,
			               |	Хрюкости.Код УБЫВ
			               |;
			               |
			               |////////////////////////////////////////////////////////////////////////////////
			               |ВЫБРАТЬ ПЕРВЫЕ 1
			               |	тПредыдущих.Дата КАК Дата,
			               |	тПредыдущих.Код КАК Код
			               |ИЗ
			               |	тПредыдущих КАК тПредыдущих
			               |
			               |УПОРЯДОЧИТЬ ПО
			               |	тПредыдущих.Дата,
			               |	тПредыдущих.Код";
			Запрос.Текст = СтрЗаменить(Запрос.Текст, "100", Формат((page - 1) * nums, "ЧДЦ=0; ЧН=; ЧГ="));
			Выборка = Запрос.Выполнить().Выбрать();
			Если Выборка.Следующий() Тогда
				ПредДата = Выборка.Дата;
				ПредКод = Выборка.Код;
			КонецЕсли;
		КонецЕсли;
		
		Запрос = Новый Запрос;
		Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 100
		               |	Хрюкости.Код КАК news_code,
		               |	Хрюкости.Дата КАК date,
		               |	Хрюкости.Наименование КАК name,
		               |	Хрюкости.Содержание КОНЕЦ КАК content,
		               |	Хрюкости.Изображение КАК image
		               |ИЗ
		               |	Справочник.ПоследниеСплетни КАК Хрюкости
		               |ГДЕ
		               |	(Хрюкости.Дата < &ПредДата)
		               |	ИЛИ
					   |	(Хрюкости.Дата = &ПредДата И Хрюкости.Код < &ПредКод)
		               |
		               |УПОРЯДОЧИТЬ ПО
		               |	Хрюкости.Дата УБЫВ,
		               |	Хрюкости.Код УБЫВ";
		Запрос.Текст = СтрЗаменить(Запрос.Текст, "100", Формат(nums, "ЧДЦ=0; ЧН=; ЧГ="));
		Запрос.УстановитьПараметр("ПредДата", ПредДата);
		Запрос.УстановитьПараметр("ПредКод", ПредКод);
		Выборка = Запрос.Выполнить().Выбрать();
		
		РезМассив = Новый Массив;
		Пока Выборка.Следующий() Цикл
			РезСтрукт = Новый Структура("news_code, date, datestr, name, content, image");
			ЗаполнитьЗначенияСвойств(РезСтрукт, Выборка);
			РезСтрукт.datestr = Формат(Выборка.date, "ДФ='dd.MM.yyyy HH:mm:ss'");
			РезМассив.Добавить(РезСтрукт);
		КонецЦикла;
		
		ЕстьЕще = Ложь;
		Если РезМассив.Количество() > 0 Тогда
			КрайняяНовость = РезМассив[РезМассив.Количество() - 1];
			Запрос = Новый Запрос;
			Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
			               |	Хрюкости.Код КАК news_code
			               |ИЗ
			               |	Справочник.ПоследниеСплетни КАК Хрюкости
			               |ГДЕ
			               |	(Хрюкости.Дата < &ПредДата)
			               |	ИЛИ
						   |	(Хрюкости.Дата = &ПредДата И Хрюкости.Код < &ПредКод)
			               |
			               |УПОРЯДОЧИТЬ ПО
			               |	Хрюкости.Дата УБЫВ,
			               |	Хрюкости.Код УБЫВ";
			Запрос.УстановитьПараметр("ПредДата", КрайняяНовость.date);
			Запрос.УстановитьПараметр("ПредКод", КрайняяНовость.news_code);
			ЕстьЕще = НЕ Запрос.Выполнить().Пустой();
		КонецЕсли;
		
		answer.result = Новый Структура("portion, havingmore", РезМассив, ЕстьЕще);
		answer.error = Ложь;
		answer.errortext = "";
		
	Исключение
		answer.errortext = ОписаниеОшибки();
	КонецПопытки;
	
	Возврат answer;
	
КонецФункции

Если вкратце, то алгоритм следующий:

  1.  Делаем выборку ВСЕХ записей, определяя, с какой записи было начало предыдущей страницы
  2. Начиная с этой записи, делаем выборку N записей
  3. Передаем результат

Интересно будет посмотреть как этот алгоритм будет вести себя при миллионах записей..