Имя: Пароль:
1C
 
Запрос в цикле
0 AlexSandra
 
09.01.25
16:23
Добрый день форумчане) с прошедшими вас праздниками и да будет процветать этот форум во веки вечные)

Есть задача: При создании номера заказа проверять его уникальность по реквизиту "Номер" который формируется из год+месяц первые четыре цифры и 0101 значение константы которое обнуляется в начале каждого месяца. Пример: 25010101
следующий номер записывается в константу как конст = конст+1.
Вроде того: ПредполагаемыйНомер = Число(ТекущийМесяцГод + конст)
Есть небольшая вероятность дублей заказов, чтобы избежать этого нужно сделать проверку уникальности "номера".

Придумано 2 решения.

В Цикле. формируется запрос ВЫБРАТЬ ПЕРВЫЕ 1 где  Заказ.Номер = &НомерЗаказа, если результат пустой и номер свободен - используем, если Иначе конст = конст+1. и повторяем запрос. Ограничив цикл, допустим 20 попытками.

Или

Формируем запрос выгрузив все номера за текущий месяц в множество и уже внутри множество ищем совпадение.

Как вариант можно не выгружать а сразу в "выборке.следующий() цикл" искать наш номер.

Какой вариант выбрать?
С одной стороны вроде "плохой тон" запрос в цикле делать, с другой стороны поддерживать легче, при небольшом потоке заказов как будто бы логично. И скорее всего ответ будет получен в первом же цикле, потому что дубли такие исключение встречающееся 1-2 раза в месяц в худшем случае..
Во втором варианте объем запроса сильно больше, но мы избегаем запроса в цикле.
Нужно ли это? как правильней? или "все фигня надо так"?

Версия 1С:Предприятие 8.1 (8.1.9.57)

Заранее спасибо)
1 программистище
 
09.01.25
16:26
Можно например сделать нумератор с периодичностью месяц, не?
2 formista2000
 
09.01.25
16:27
Есть же периодичность нумерации в пределах месяца...
3 arsik
 
гуру
09.01.25
16:28
(0) Глупость какая. Есть платформенные инструменты для этого (префикс номера), без использования констант.
Просто посмотрите стандартные конфигурации на БСП.
4 Fedor-1971
 
09.01.25
16:34
(0) Блокируй константу при получении значения, увеличивай на 1 и записывай и будет тебе счастье т.к. остальные документы будут ждать снятия блокировки
Только лучше переделать на Регистр сведений, т.к. в следующем году надо начать с 1, и могут довносить старые заказы в прошлый год
5 Fedor-1971
 
09.01.25
16:33
(2) В пределах месяца нумератор сбросится на 1 в следующем месяце, как я понял, ТС надо общая нумерация всех заказов и префикс ММГГ
6 AlexSandra
 
09.01.25
16:41
Тут есть нюанс, иногда человеческий фактор включается и рееедко (потому что круг лиц ограничен но он все же есть), заказ меняется вручную...ну вот так Меркурий встал. Заблочить смену номера в моем случае не вариант. Но проверку сделать, чтобы стандартный счетчик в итоге не сделал дубль - хочется. Раз уж огород городить приходиться, хотелось сделать максимально разумно из возможного.
7 mTema32
 
09.01.25
16:45
(0) Заведите регистр сведений где будут хранится все номера. При формировании нового, берете последний и делаете инкримент.
При редактировании вручную можно также из этого РС брать запросом номер и далее уведомлять что мол такой уже есть, ну или что-то другое в зависимости от бизнес-процесса.
8 Fedor-1971
 
09.01.25
16:50
(6) При изменении заказа номер ему уже присвоен. Не?
9 Fedor-1971
 
09.01.25
16:57
(6) Вот тебе пример: (если очень приспичит, то присвой номер прямо из формы документа в ПередЗаписью в своей транзакции - остальные не смогут получить номера минимальное время)
Присвоение Номера карточки ОС через константу, сплошной чистый инкремент
Инвентарный номер - присваивается чисто в разрезе счёта учёта (вот такая засада встречается)
        Блокировка = Новый БлокировкаДанных;
        ЭлементБлокировки = Блокировка.Добавить("Константа.ОСНомерКарточки");
        ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;

        ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ОСИнвентарныеНомера");
        ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
        ЭлементБлокировки.ИсточникДанных = тзСчетов;
        ЭлементБлокировки.ИспользоватьИзИсточникаДанных("СчетУчета", "СчетУчета");
        Блокировка.Заблокировать();
        
        инф.Текст =
            "ВЫБРАТЬ
            |    таб.СчетУчета КАК СчетУчета,
            |    таб.ПоследнийНомер КАК ПоследнийНомер
            |ИЗ
            |    РегистрСведений.ОСИнвентарныеНомера КАК таб
            |ГДЕ
            |    таб.СчетУчета В
            |            (ВЫБРАТЬ
            |                табОснова.СчетУчетаБУ
            |            ИЗ
            |                табОснова)";
        текИнвНомераПоСчетам = инф.Выполнить().Выгрузить();
        текКарточкаОС = Константы.ОСНомерКарточки.Получить();
        НетОшибок = Истина;
        
        Для каждого текОС из тзОС цикл
            обОС = текОС.ОсновноеСредство.ПолучитьОбъект();
            Если текОС.ИнвентарныйНомер = "" тогда
                мас = текИнвНомераПоСчетам.НайтиСтроки(новый Структура("СчетУчета", текОС.СчетУчетаБУ));
                
                Если мас.Количество() тогда
                    мас[0].ПоследнийНомер = мас[0].ПоследнийНомер + 1;
                    обОС.НомерИнвентарный = СокрЛП(текОС.СчетУчетаБУ) + Формат(мас[0].ПоследнийНомер, "ЧЦ=9; ЧВН=; ЧГ=0");
                КонецЕсли;
            КонецЕсли;
            
            Если текОС.НомерКарточки_гху = "" тогда
                текКарточкаОС = текКарточкаОС + 1;
                обОС.НомерКарточки_гху = Формат(текКарточкаОС, "ЧЦ=10; ЧГ=0");
            КонецЕсли;
            
            Попытка
                обОС.Записать();
                
            Исключение
                Отказ = Истина;
                НетОшибок = Ложь;
                Сообщить("Ошибка записи ОС: " + СокрЛП(текОС.ОсновноеСредство) + ": " + ОписаниеОшибки());
            КонецПопытки;
        КонецЦикла;
10 Fedor-1971
 
09.01.25
17:04
9+ По уму, тебе нужен РС (Год, ТекущийНомер) и проверка номера документа на соответствие дате, т.е.
если документ двигают в пределах месяца, то всё норм, новый номер не нужен,
если перенесли в другой, то присваиваем новый номер
11 AlexSandra
 
09.01.25
17:25
(10) Проверка документа на соответствие не нужно, там ориентир на момент создания, он может несколько месяцев висеть не страшно, удобно искать концы по препискам и тд. Хотелось бы не меняя в общем логику, которая сейчас есть просто добавить проверку. 1С старая, во всю рабочая. Параллельно делается новая на которую планируют перейти, всерьез перепиливать старую как будто бы не особо актуально. Блокировка данных - разумно, но тут идея в том что номер заказа могут поменять в большую или меньшую сторону, случайно или по непреднамеренной кривизне рук. Т.е. должен быть 101, а изменился на 110, счетчик остался на 101, потом пошел +1,+1 и дошел до 110, вот в момент совпадения, чтобы он просто проскочил его и создал следующий 111
12 AlexSandra
 
09.01.25
17:26
отправила и подумала что в редких случаях номер могут и уменьшить. Там бы тоже хорошо проверить на уникальность
13 Garykom
 
гуру
09.01.25
17:35
(0)
1. Константа нафик не нужна
Просто запрос к Номер с упорядочиванием по убыванию и получение первого
Возможно понадобится ПОДОБНО
Операции с константой иногда будут затратней

2. Перед или ПриЗаписи еще раз проверить на дублирование снова запросом уже с конкретным сформированным Номер
Если дубль - заново делаем п.1
14 AlexSandra
 
09.01.25
17:42
(13) Но мне нужно обновлять последние четыре цифры каждый месяц, народ так привык им удобней. И начальный номер там всегда 101.
15 Garykom
 
гуру
09.01.25
17:44
(14) ну так и обновляй
я же написал про ПОДОБНО
часть Номер известна, получаешь список подходящих, сортируешь - имеешь последний в базе
берешь изменяемую часть (счетчик) и делаешь +1, формируешь новый номер
16 Волшебник
 
09.01.25
17:47
(0) >> Добрый день форумчане) с прошедшими вас праздниками и да будет процветать этот форум во веки вечные)

💖
17 craxx
 
10.01.25
04:30
(0)
Версия 1С:Предприятие 8.1 (8.1.9.57)

А еще более музейную взять слабо?
18 Адинэснег
 
10.01.25
05:47
Перед записью в модуле объекта для нового объекта:
Ставишь управляемую блокировку на таблицу этого документа, получаешь запросом максимум (никаких циклов, агрегатной функцией по полю номер)
Присваиваешь номеру максимум+1
Снимаешь упр. блокировку
19 maxab72
 
10.01.25
08:32
Делал похожее. В месяц было не много документов, сотни две-три максимум. При создании нового документа выгружал запросом все номера документов за месяц в массив, и в цикле последовательно создавал номера документов, начиная с первого. Если такой номер в списке ранее созданных уже был, брал следующий, если не было - присваивал документу его. Задача была не допускать пропусков в номерах, так как документы часто перебрасывались из месяца в месяц (это были производственные планы) с заменой номера.
20 Прохожий
 
10.01.25
09:02
"Придумано 2 решения." давно таких людей на форуме не было...
21 AlexSandra
 
10.01.25
09:11
(18) А если у меня счетчик с 101 идет, а ручками кто-то 850 назначил, мне максимум не с руки делать, нужно продолжить последовательность 101, до 850 можем и не дойти за месяц
22 AlexSandra
 
10.01.25
09:12
(20) Вы о чем?
23 AlexSandra
 
10.01.25
09:13
(19) Спасибо
24 AlexSandra
 
10.01.25
09:14
(16) А вы посоветовать можете? вы обычно очень толковые советы даете
25 Fedor-1971
 
10.01.25
10:07
(11) тогда запросом проверь есть ли такой номер. Пример в (9) чисто показать как работает, ни кто не запрещает доработать под свои условия.
Например, так: берём новый номер, проверяем существующие документы на совпадение исключая ссылку текущего, если что не так, то берём следующий
26 d4rkmesa
 
10.01.25
10:25
(0) Вас кто-то из под палки заставляет все именно так делать? А реквизит Номер стандартный вообще?
Обычно это решается иначе, в (3) написали, ГГММ добавляется как префикс, если нужно. Дальше работают платформенные механизмы.
В крайнем случае можно сделать как в (18), только лучше в обработчике ПриУстановкеНовогоНомера нужного документа.
27 Garykom
 
гуру
10.01.25
10:51
(21) Назначить новый номер могут любой
Полагаться на это нельзя
Если такой назначили значит надо и нумерацию с него продолжать самое простое
А не полагаться на влезем - не влезем
28 Lite777888
 
naïve
10.01.25
14:54
(9) НачатьТранзакцию();

    Попытка
        ... // чтение или запись данных
        ДокументОбъект.Записать()
        ЗафиксироватьТранзакцию();
    Исключение
        ОтменитьТранзакцию();
        ... // дополнительные действия по обработке исключения
    КонецПопытки;
29 Lite777888
 
naïve
10.01.25
15:00
(0) Документы, нумераторы ,добавить
30 Волшебник
 
10.01.25
16:39
(24) Присваивайте номер не при открытии формы нового, а при записи документа.
31 Eiffil123
 
10.01.25
17:25
(0) про запрет на запрос в цикле - это пиздеж. в вашем примере он будет являться скорее исключением. делайте
32 Fedor-1971
 
11.01.25
09:12
(31) В данном случае он излишен т.к. 20 (в общем случае N) циклов проверки номера не гарантируют, что он не повторится
Пример, кто-то начал писать чуть раньше - получил номер, его 20 циклов закончились примерно в конце 20 цикла проверки - оба получили ОК и радостно записали одинаковые номера документов
33 МайскаяГроза
 
11.01.25
16:33
(9) в коде можешь объяснить зачем два раза выбираешь
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;

Это что-то с религией связано?
34 Garykom
 
гуру
11.01.25
17:35
(33) разные элементы же
35 Fedor-1971
 
13.01.25
09:05
(33) первый раз - блокируем константу, второй - часть РС по нужным счетам
36 Fedor-1971
 
13.01.25
09:09
(28) Это чистый пример, но если оный положить в ОбработкаПроведения - транзакция уже есть и смысла плодить дополнительную нет
37 Fedor-1971
 
13.01.25
09:16
(29) Нумераторы - это единая нумерация нескольких видов документов, например, есть 2 вида заказов: на канцелярку и на приобретение ТМЦ, но у оных должна быть единая сквозная нумерация
38 программистище
 
13.01.25
10:37
Еще можно попробовать сделать нумератор (как  я писал в(1)) подцепить к нему свой документ, без движений и пр.
формировать первый документ в 00:00:00 с номером 250113000 (например регламентом)
и дальше номера сами будут формироваться для остальных документов (если нужно еще по префиксу организации, то формировать для каждого префикса)
ну это самое простое, без запросов, и блокировок
39 GANR
 
13.01.25
09:51
(0) Запрос, который в секции ГДЕ ищет минимальный номер, после которого нет следующего. Но это всё равно костыль - надо ограничиться автонумератором и закрыть ручную правку номера от криворучек.
40 Kongo2019
 
13.01.25
10:33
(0) а если сразу несколько операторов пойдут номер искать?
Закон Брукера: Даже маленькая практика стоит большой теории.