Как в запросе выбрать из справочника несколько случайных элементов?

1. ildarovich 7861 29.03.15 11:06 Сейчас в теме
Один способ я знаю. Интересует: есть ли другие способы?
По теме из базы знаний
Вознаграждение за ответ
Показать полностью
Найденные решения
87. vugluscr1991 12 03.04.15 14:34 Сейчас в теме
Окончательно:
	РезультатВыборки = Новый Массив;
	
	ПервоначальнаяТаблица = Новый ТаблицаЗначений;
	ПервоначальнаяТаблица.Колонки.Добавить("Товар", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
	
	Для СчЭлементов = 1 По 2 * НадоСлЭлементов Цикл
		Номенклатура = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор());
		СслкаИД = Номенклатура.УникальныйИдентификатор(); // Нового().УникальныйИдентификатор();
		
		ПервоначальнаяТаблица.Добавить().Товар = Номенклатура;
	КонецЦикла;
	
	
		Запросо = Новый Запрос;
		Запросо.Текст = "ВЫБРАТЬ
		                |	НедействительныеСсылки.Товар КАК Товар
		                |ПОМЕСТИТЬ Товары
		                |ИЗ
		                |	&НедействительныеСсылки КАК НедействительныеСсылки
		                |
		                |ИНДЕКСИРОВАТЬ ПО
		                |	Товар
		                |;
		                |
		                |////////////////////////////////////////////////////////////­////////////////////
		                |ВЫБРАТЬ
		                |	МАКСИМУМ(ЕСТЬNULL(Номенклатура.Ссылка, ПервыйЭлемент.Ссылка)) КАК Номенклатура,
		                |	НедействительныеСсылки.Товар
		                |ПОМЕСТИТЬ ВсякаБяка
		                |ИЗ
		                |	Товары КАК НедействительныеСсылки
		                |		ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ ПЕРВЫЕ 1
		                |			Номенклатура.Ссылка КАК Ссылка
		                |		ИЗ
		                |			Справочник.Номенклатура КАК Номенклатура
		                |		ГДЕ
		                |			Номенклатура.ЭтоГруппа = ЛОЖЬ) КАК ПервыйЭлемент
		                |		ПО (ИСТИНА)
		                |		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
		                |		ПО НедействительныеСсылки.Товар >= Номенклатура.Ссылка
		                |			И (Номенклатура.ЭтоГруппа = ЛОЖЬ)
		                |
		                |СГРУППИРОВАТЬ ПО
		                |	НедействительныеСсылки.Товар
		                |;
		                |
		                |////////////////////////////////////////////////////////////­////////////////////
		                |ВЫБРАТЬ РАЗЛИЧНЫЕ ПЕРВЫЕ " + Формат(НадоСлЭлементов, "ЧГ=") + "
		                |	ВсякаБяка.Номенклатура
		                |ИЗ
		                |	ВсякаБяка КАК ВсякаБяка";
		
		Запросо.УстановитьПараметр("НедействительныеСсылки",ПервоначальнаяТаблица);				
		//Запросо.УстановитьПараметр("Массиво", РезультатВыборки);
		
		РезЗапроса = Запросо.Выполнить();
		Если Не РезЗапроса.Пустой() Тогда
		
			СлучайныеТовары.ЗагрузитьЗначения(РезЗапроса.Выгрузить().ВыгрузитьКолонку("Номенклатура"));
			СлучайныеТовары.СортироватьПоЗначению(НаправлениеСортировки.Возр);
		КонецЕсли;
		
		Сообщить(СлучайныеТовары.Количество());
Показать
yghmd; METAL; +2 Ответить
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
107. vugluscr1991 12 05.04.15 12:17 Сейчас в теме
(106) ildarovich,
выбор будет более случайным

просто случайным, пока было мало испытаний, с увеличением числа испытаний появится статистика по "удачным водителям" и случайность (при таком взгляде на её качество) ухудшится. Я лишь выдвигаю гипотезу о том, что малое число испытаний - не такое уж и малое и может составлять не менее 10% от мощности справочника.
Обращаясь к своей статистике и получая на выборках из 66 000 элементов 630 уникальных из 700 испытаний я вижу, что отношение себестоимости выявления нетрезвого водителя у меня и у моего идеального конкурента не будет 1:2.
И да, про тиражное решение полностью согласен, не согласен лишь с определением такой выборки, как случайной и опять же с философских позиций: у нас есть к ней некоторое практическое требование о равномерности покрытия и извлечении из этого регулярной практической пользы. Мы могли бы в таком случае взять некоторую математически определенную функцию выборки, которую невозможно воспроизвести "на коленке" или реверсом, но которая гарантированно покроет весь справочник. И тогда у нас останется лишь одна проблема - утечка алгоритма от разработчиков. Что, вероятно случайно (сик! сарказм) и произошло с таможенной программой.
108. ildarovich 7861 05.04.15 23:02 Сейчас в теме
(107) vugluscr1991, задачи теория вероятностей и ее приложений настолько хорошо изучены, что все, о чем мы с вами говорим, можно обсчитать по формулам, даже не проводя численных экспериментов. Есть критерии равномерности распределения, связывающие число испытаний с уверенностью в одной из гипотез, можно очень точно экономику по водителям посчитать. Кажется, что число коллизий и затраты на проверку прямо не связаны и 1 : 2 вполне может быть. Кстати, "парадокс дней рождения" говорит о том, что коллизий все таки многовато. При таком соотношении (66000 = 2^16 и 700 ~ 2^9) при хорошем ГСЧ должна быть всего пара коллизий. Но не хочу сейчас тратить время на эти школярские задачи, обсчитывая "запасной" метод.
Вариант
взять некоторую математически определенную функцию выборки, которую невозможно воспроизвести "на коленке" или реверсом, но которая гарантированно покроет весь справочник
это и есть основа любого ГПСЧ. Но кроме того для рассматриваемых задач ГСЧ к функции добавляется энтропия или "соль" в виде текущего времени и тому подобного. Так и построено то мое решение, спарринг к которому я хотел найти.
Из всех предложенных других решений ваше решение оказывается на данный момент лучшим. Так что вопрос выбора в данной теме закрываю.
Если можно было бы назначать вознаграждение за второе и третье место, то их бы получили решения (36) и (11) соответственно.
Тем не менее любые новые соображения по этой теме всегда будут приветствоваться.
88. Vint_1c 25 03.04.15 14:43 Сейчас в теме
Вот мой вариант накиданный на скорую руку, всегда выдает случайность.

	ТекстЗапроса = "
	|ВЫБРАТЬ
	|	КОЛИЧЕСТВО(Контрагенты.Ссылка) КАК КОЛ
	|ИЗ
	|	Справочник.Контрагенты КАК Контрагенты
	|;";
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	ВЫБОРКА = Запрос.Выполнить().Выбрать();
	ВЫБОРКА.Следующий();
	КолВСправочнике = ВЫБОРКА.Кол;
	
	ГенераторСЧ = Новый ГенераторСлучайныхЧисел;
	ЧислоСЧ = ГенераторСЧ.СлучайноеЧисло(1,КолВСправочнике);
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	Контрагенты.Ссылка,
	|	1 КАК НомерСтроки
	|ПОМЕСТИТЬ ВТ
	|ИЗ
	|	Справочник.Контрагенты КАК Контрагенты
	|;
	|
	|////////////////////////////////////////////////////////////­////////////////////
	|ВЫБРАТЬ
	|	Контрагенты.Ссылка,
	|	СУММА(ВТ.НомерСтроки) КАК НомерСтроки
	|ПОМЕСТИТЬ ВТКонтрагентыНумерация
	|ИЗ
	|	Справочник.Контрагенты КАК Контрагенты
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ КАК ВТ
	|		ПО Контрагенты.Ссылка <= ВТ.Ссылка
	|
	|СГРУППИРОВАТЬ ПО
	|	Контрагенты.Ссылка
	|;
	|
	|////////////////////////////////////////////////////////////­////////////////////
	|ВЫБРАТЬ
	|	ВТКонтрагентыНумерация.Ссылка,
	|	ВТКонтрагентыНумерация.НомерСтроки
	|ИЗ
	|	ВТКонтрагентыНумерация КАК ВТКонтрагентыНумерация
	|ГДЕ
	|	ВТКонтрагентыНумерация.НомерСтроки = &ГенераторСЧ
	|
	|УПОРЯДОЧИТЬ ПО
	|	ВТКонтрагентыНумерация.НомерСтроки" ;
	Запрос.УстановитьПараметр("ГенераторСЧ",ЧислоСЧ);
	Выборка = Запрос.Выполнить().Выбрать();
	
	Выборка.Следующий();
	
	Сообщить(Строка(Выборка.Ссылка) + "  НомерСтроки" +  Строка(Выборка.НомерСтроки));
Показать
91. ildarovich 7861 03.04.15 14:54 Сейчас в теме
(88) Vint_1c, тут не хорошо то, что время работы запроса для нумерации контрагентов будет квадратично зависеть от размера этого справочника. Сколько контрагентов было при экспериментах. Сколько времени работал запрос?
Чтобы проверить эту гипотезу, нужно вот этот кусок исправить так
ВЫБРАТЬ
    |    Контрагенты.Ссылка,
    |    1 КАК НомерСтроки
    |ПОМЕСТИТЬ ВТ
    |ИЗ
    |    Справочник.Контрагенты КАК Контрагенты 
    |ОБЪЕДИНИТЬ ВСЕ
    |ВЫБРАТЬ
    |    Контрагенты.Ссылка,
    |    0
    |ИЗ
    |    Справочник.Контрагенты КАК Контрагенты
Показать
по идее, время должно вырасти примерно в четыре раза. Для больших справочников это будет существенно.
90. Vint_1c 25 03.04.15 14:51 Сейчас в теме
А Забыл добавить, чтобы было несколько элементов, нужно сгенерить тогда массив чисел и в запросе изменить строку | ВТКонтрагентыНумерация.НомерСтроки = &ГенераторСЧ на | ВТКонтрагентыНумерация.НомерСтроки В (&ГенераторСЧ)

Это относится к моему ответу выше.
92. Vint_1c 25 03.04.15 15:02 Сейчас в теме
Секунд 7-8 для справочника с количеством элементов 37000.
94. ildarovich 7861 03.04.15 15:23 Сейчас в теме
(92) Vint_1c, база SQL или файловая? Эксперимент по удвоению не могли бы провести?
95. Vint_1c 25 03.04.15 15:44 Сейчас в теме
(94) ildarovich, ,база SQL, я слегка обманул по поводу 7-8 секунд,
замеры следующие,
при первоначальном запросе было 1.5 минуты
после добавления вашего куска стало 3 минуты
Медленно, нужно подумать над этим вопросом.
93. kudlach 12 03.04.15 15:03 Сейчас в теме
Насколько помню теорию математики для образования случайного числа - делится одно число (например 1) на простое число (например 17) . Берешь, скажем, 4 цыфру, делим ее еще раз, и так по циклу , скажем, число раз равное показателю секунд на момент начала процедуры.
в качестве знаков после запятой в цифре 0,11111 берется результат тоже начиная с какой-то цифры. Получаем показатель, который нужно умножить на количество контрагентов. Результатом будет номер контрагента.

Алгоритмов получения случайного числа много, они все неидеальны, т.к. страдают тем что нет абсолютного нормального распределения вероятности.
97. vtools 72 03.04.15 16:45 Сейчас в теме
Вот такой код выдает интересный результат:
	

	Запрос=Новый Запрос;
	Запрос.Текст="ВЫБРАТЬ ПЕРВЫЕ 1
	             |	Контрагенты.Ссылка КАК Ссылка
	             |ИЗ
	             |	Справочник.Контрагенты КАК Контрагенты
	             |ГДЕ
	             |	Контрагенты.Ссылка > &Ссылка";
				 
	СлучИД=Справочники.Контрагенты.ПолучитьСсылку(Новый УникальныйИдентификатор());
	Запрос.УстановитьПараметр("Ссылка",СлучИД);
	ТЗ=Запрос.Выполнить().Выгрузить();
	ТЗ.ВыбратьСтроку();


Показать



Минус - значения повторяются :) Мне кажется из-за неправильного использования УникальныйИдентификатор() в качестве ГСЧ.
Если сформировать УИД самостоятельно, через обычный ГСЧ, то должно получиться (т.е. сделать обратное действие, которое описывается в ответе 14).
109. SpecRam 34 19.03.16 22:30 Сейчас в теме
Добрый день!

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

// Получить случайные слова
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Слова.Ссылка КАК Слово
		|ИЗ
		|	Справочник.Слова КАК Слова
		|ГДЕ
		|	Слова.Владелец = &Владелец";
	
	Запрос.УстановитьПараметр("Владелец", Объект.Словарь);
	
	ТЗ = Запрос.Выполнить().Выгрузить();
	КолВоЭлементов = ТЗ.Количество();
	
	// Формирование ГСЧ
	ГСЧ = Новый ГенераторСлучайныхЧисел(ТекущаяДата()-НачалоДня(ТекущаяДата()));
	
	Для Ном=1 По Объект.КоличествоСлов Цикл
		
		НомерСлова = ГСЧ.СлучайноеЧисло(1, КолВоЭлементов);
		
		НоваяСтрока = Объект.СписокСлов.Добавить();
		НоваяСтрока.СловоЗапом = ТЗ[НомерСлова-1].Слово;
        КонецЦикла;
Показать
110. ildarovich 7861 19.03.16 23:50 Сейчас в теме
(109) SpecRam, вы пропустили первое слово в условии задачи "В ЗАПРОСЕ", а у вас еще ко всему и несколько раз один и тот же элемент выбирается. Кроме того, инициализация и так текущим временем производится, не нужно заморочек в скобках.
113. user1991482 22.02.24 14:57 Сейчас в теме
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
|	1 КАК Ном,
|	Таблица.Товар КАК Товар
|ИЗ
|	Справочник.Товары КАК Таблица";

Результат = Запрос.Выполнить.Выгрузить();

ГСЧ = Новый ГенераторСлучайныхЧисел;

Для Каждого Стр Из Результат  Цикл
    Стр.Ном = ГСЧ.СлучайноеЧисло(1, 100000);
КонецЦикла;

Результат .Сортировать("Ном");
 
Ном = 0;
Для Каждого Стр Из Результат Цикл
        // Количество необходимых случайных записей
        // Выполнится либо полный цикл по таблице (кол-ву элементов справочника, либо по "Ном")
	Если Ном = 3 Тогда
		Прервать;
	КонецЕсли;

	Сообщить(Стр.Товар);
	Ном = Ном + 1;
КонецЦикла;
Показать
114. Said-We 22.02.24 15:24 Сейчас в теме
(113) Это не запросом. Запросом это условно так (в постах в начале, по моему был такой вариант, если это та ветка):
https://onecompiler.com/sqlserver/4257m4q5v

Только автору надо ещё убрать повторяющиеся. Можно прям в рекурсивном запросе, ещё одно условие и там же генерацию.
Можно выбрать заведомо больше, свернуть и взять первых нужное количество. Вариантов много.
Ветка 2015-2016 года и автор знал ответ заранее.
Прикрепленные файлы:
115. user1991482 22.02.24 17:00 Сейчас в теме
(114) И как использовать такой вариант в 1с8?
116. Said-We 23.02.24 22:21 Сейчас в теме
(115) Внутри никак. Этот вопрос не ко мне, а к разработчикам 1С. Запросы в 1С очень скудные по своему функционалу.
А как внешний вызов использовать никто не запрещает и не сложно. Но автор такой вариант и так знает.
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот