Как постранично (порционно) листать результат запроса в 1С (ака LIMIT x,y в MySQL)
Большая беда MSSQL и как следствие 1С — отсутствие возможности порционно листать записи результата запроса как в MySQL. В результате рождаются такие монстроузные алгоритмы как ниже (код не мой):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
Функция 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; КонецФункции |
Если вкратце, то алгоритм следующий:
- Делаем выборку ВСЕХ записей, определяя, с какой записи было начало предыдущей страницы
- Начиная с этой записи, делаем выборку N записей
- Передаем результат
Интересно будет посмотреть как этот алгоритм будет вести себя при миллионах записей..