Формирование числового идентификатора

1. D.Gal 9 14.08.17 16:00 Сейчас в теме
Здравствуйте, форумчане.

Есть такой вопрос:
Мне необходимо сделать уникальный в пределах справочника идентификатор из 16 цифр.
Пользовался 2-умя разными способами, но ни один не привел к успеху. Через какое то время появляются дубли. Не пойму как.
Способ 1:

Функция СоздатьЧисловойГУИД(Спр) Экспорт   
	ГУИД = "";
	Строка = "0123456789";
	ГЧС = Новый ГенераторСлучайныхЧисел(); 
	Пока СтрДлина(ГУИД)<=16 Цикл
		ГУИД = ГУИД + Сред(Строка, ГЧС.СлучайноеЧисло(0,СтрДлина(Строка)), 1);		
	КонецЦикла;	
	 
	Если ПоискЧисловогоГУИДа(Строка(ГУИД), Спр) = Ложь Тогда
		Возврат ГУИД;
	Иначе
		СоздатьЧисловойГУИД(Спр);
	КонецЕсли;
КонецФункции	
Показать


Способ 2:
Функция СоздатьЧисловойГУИД(Спр) Экспорт
	Попытка
		ScrptCtrl = новый COMОбъект("MSScriptControl.ScriptControl");
	    ScrptCtrl.Language="javascript";
		Код = "function randomInteger(min, max){
				|var rand = min - 0.5 + Math.random() * (max - min + 1);
				|rand = Math.round(rand);
				|return rand;
				|}";
		ScrptCtrl.AddCode(Код);
		//СтрокаВыполнения = "randomInteger(" + мин + "," + СтрЗаменить(макс, Символы.НПП, "") + ")";
		СтрокаВыполнения = "randomInteger(0, 9999999999999999)";
		Ответ = ScrptCtrl.Eval(СтрокаВыполнения);
		УИДСтрокой = СтрЗаменить(Ответ, Символы.НПП, "");
		Если СтрДлина(УИДСтрокой) < 16 Тогда
			Для сч = 0 По 16 - СтрДлина(УИДСтрокой) - 1 Цикл
				УИДСтрокой = "0" + УИДСтрокой;
			КонецЦикла;
		КонецЕсли;
		
		Если ПоискЧисловогоГУИДа(УИДСтрокой, Спр) = Ложь Тогда
			Возврат УИДСтрокой;
		Иначе
			СоздатьЧисловойГУИД(Спр);
		КонецЕсли;
	Исключение
		СоздатьЧисловойГУИД(Спр);
	КонецПопытки;	
КонецФункции
Показать


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


Есть кое-какие вещи излишние, например, ряд условий. На текущий момент все находится в тесте, на боевой базе не используется, но даже в тестовой базе умудряются появиться дубли.

Помогите, пожалуйста, что не так?
По теме из базы знаний
Найденные решения
22. spacecraft 15.08.17 11:41 Сейчас в теме
(21) все намного проще:
Гуид = Формат(ТекущаяУниверсальнаяДатаВМиллисекундах(), "ЧЦ=16; ЧВН=; ЧГ=0");

Если уже есть коды, то сделать проверку не сложно.

Если уже имеющиеся коды не сильно завязаны на конкретные значения, то можно их все перегенерировать по новой системе.
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
3. WasiliyMay 8 14.08.17 16:13 Сейчас в теме
(1) А длины поля в справочнике хватает? и нет ли лишних символов в кодах?
9. D.Gal 9 14.08.17 23:00 Сейчас в теме
(3) Хватает, лишних символов нет, функции смотрите
4. Boneman 298 14.08.17 16:25 Сейчас в теме
(1) чем код справочника не устраивает ? Это ведь и есть по своей сути уникальный идентификатор, ну сделайте его 16 значным и все.
А генератор случайных чисел, - это немного не то...Случайный - не значит уникальный.
10. D.Gal 9 14.08.17 23:01 Сейчас в теме
(4) При удалении данных такой идентификатор больше не должен встретиться
2. caponid 14.08.17 16:03 Сейчас в теме
а этот идентификатор должен быть случайным и неупорядоченным?
8. D.Gal 9 14.08.17 22:59 Сейчас в теме
(2) Должен быть случайным и неупорядоченных в пределах справочника
5. user618912_redgad 13 14.08.17 16:29 Сейчас в теме
Используйте поле с типом значения УникальныйИдентификатор()
Ну и заполняйте его:
Спр.Ид = Новый УникальныйИдентификатор();
11. D.Gal 9 14.08.17 23:03 Сейчас в теме
(5) Только 16 символов, 36 мне не надо, плюс там есть "-".
6. Boneman 298 14.08.17 16:38 Сейчас в теме
как вариант можно самодельную функцию присобачить, с привязкой ко времени.
генератором двигаете знаков 8-10, и добавляете количество , например минут с определенной точки отсчета...н-р, начало этого года.
В году 525600минут в одном году, лет на 10 запас сделать и все
12. D.Gal 9 14.08.17 23:07 Сейчас в теме
(6) Вот самое интересное, что уникальности алгоритм позволяет добиться так как после генерации происходит проверка на существование в базе. Вот тут проблема и кроется. Проходит неделя две и появляется дубль в базе. Запрос проверяет наличие каждый раз, но все же получается что платформа в запросе даёт нулевой результат, следовательно создаётся ещё один ИД, который в базе есть. Только как я не понимаю?
7. starik-2005 3039 14.08.17 16:40 Сейчас в теме
УИ = ТекущаяУниверсальнаяДатаВМиллисекундах();
13. user618912_redgad 13 15.08.17 07:15 Сейчас в теме
Создаешь новый справочник. Тип номера - числовой. Длина номера - 16.
В твой справочник добавляешь реквизит с типом созданного справочника.
Ну и при записи создаешь новый элемент справочника и записываешь ссылку на него в добавленный реквизит.
ipoloskov; +1 Ответить
14. comptr 31 15.08.17 07:20 Сейчас в теме
Ещё вариант:
Создаешь регистр сведений, куда записываешь кучу заранее сгенерированных идентификаторов, а потом случайным образом из них выбираешь любой и удаляешь его из регистра.
Нагенерировать следующую порцию будет сложнее, зависит от того, как генерировалось изначально. Если были взяты числа подряд с начала, то надо будет просто помнить последнее число, и продолжить генерировать начиная с него. Иначе придется собирать числа, которые уже были использованы и удалены из регистра.
15. ditp 91 15.08.17 09:59 Сейчас в теме
(14) Ага, https://habrahabr.ru/post/324772/

(1) а при копировании элементов у вас точно новый гуид генерится?

Ну и лучше сразу несколько гуидов-кандидатов создать и сразу по ним всем проверить, чем рекурсиями и запросами в цикле заниматься.
18. D.Gal 9 15.08.17 11:02 Сейчас в теме
(15) копирование запрещено
16. timeforlive 15 15.08.17 10:09 Сейчас в теме
Чтобы сгенерить случайное число, берите все имеющиеся значения запросом, помещайте их в таблицу значений, сортируйте. Далее, если нужен новый ГУИД, Берите последнее значение и добавляйте единицу.
Если нужно прямо генерировать, то сделайте следущим образом:
1. Таблицу значений нужно создавать с двумя колонками (ГУИД и КоличествоКопий. В запросе для "КоличествоКопий" ставите единицу - 1);
1. Создаете генерацию кода.
2. Добавляете в таблицу значений
3. Сворачиваете таблицу по ГУИД с суммированием колонки "КоличествоКопий".
4. Поиск в колонке КоличествоКопий = 2
5. Если неопределено, то вы создали уникальный код.
6. Если есть дубль, то генерировать новый не нужно. Делаете следующее:

а) Начинаете перебор коллекции (таблицы значений) с места, где был зафиксирован дубль
б) Прибавляете единицу к ГУИДу и сравниваете с текущим значением в итерации
в) До тех пор, пока не ГУИД не станет уникальным (если значений тьма, можно придумать функцию по поиску "пробела" между группой цифр).
17. Boneman 298 15.08.17 10:48 Сейчас в теме
Не знаю, я бы не заморачивался со всякими проверками...
смещение даты использовать да и все.
Текущая дата, в минутах, или секаундах - это по факту счетчик, который нам даст уникальность..ну и генератором генерим код. Потом соединяем, и получаем уникальное число, даже если генератор выдал повторяющийся код.
например,
5000001 минута+генератор выдал 2
5000002 минута генератор выдал 38
5000010 минута генератор выдал снова 2
но по факту число все равно уникальное.
500000102, 500000238,500001002

главное чтобы в одну и ту же минуту, у нас генератор не выдал одинаковое число..но тут вероятность много ниже, чем в разрезе недель месяцев или лет.
Хотя и с этим можно бороться..добавлять в конец числа текущую секунду
21. D.Gal 9 15.08.17 11:22 Сейчас в теме
(17) сделал еще 3-ий вариант через

ТекущаяУниверсальнаяДатаВМиллисекундах()

но когда получает значение 63 638 542 123 123
то приходится делать

СтрЗаменить(УИД, Символы.НПП, "");

А после добавлять нули в начале, так как длина строки не 16 символов
Проверка все равно нужна, так как в базе уже присутсвуют идентификаторы других элементов
УИД должен быть строковый.

Неудивлюсь, если через неделю увижу дубли.
22. spacecraft 15.08.17 11:41 Сейчас в теме
(21) все намного проще:
Гуид = Формат(ТекущаяУниверсальнаяДатаВМиллисекундах(), "ЧЦ=16; ЧВН=; ЧГ=0");

Если уже есть коды, то сделать проверку не сложно.

Если уже имеющиеся коды не сильно завязаны на конкретные значения, то можно их все перегенерировать по новой системе.
23. D.Gal 9 15.08.17 11:47 Сейчас в теме
(22)
Формат(ТекущаяУниверсальнаяДатаВМиллисекундах(), "ЧЦ=16; ЧВН=; ЧГ=0");

Я думаю этот способ попробую. Спасибо
19. ipoloskov 162 15.08.17 11:06 Сейчас в теме
создайте вспомогательный независимый регистр с измерением - ГУИД. При создании элемента справочника добавляйте запись в регистр, при удалении - не удаляйте.
Вообще странно, что рандом на 16-значном числе выдает дубли. Значит, кривой какой-то алгоритм рандома.
20. user633533_encantado 11 15.08.17 11:09 Сейчас в теме
Почему просто нельзя вести числовую последовательность и при записи нового элемента выбирать запросом последний номер и прибавлять единицу ?
24. D.Gal 9 15.08.17 12:01 Сейчас в теме
Функция СоздатьЧисловойГУИД(Спр) Экспорт
	УИД = Формат(ТекущаяУниверсальнаяДатаВМиллисекундах(), "ЧЦ=16; ЧВН=; ЧГ=0");
	Если Не Справочники[Спр].НайтиПоРеквизиту("УИД", УИД) = Справочники[Спр].ПустаяСсылка() Тогда
		СоздатьЧисловойГУИД(Спр);
	Иначе
		Возврат УИД;
	КонецЕсли;
КонецФункции


Сделал таким образом.
Оставьте свое сообщение

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