Имя: Пароль:
1C
1С v8
Найти и использовать пропущенный номер
0 cry_san
 
17.04.13
05:27
Здравствуйте!
Есть справочник без сторонних реквизитов (только Код и Наименование). Код можно заполнять произвольно, но стоит галочка на уникальность.
Как можно (и можно ли) ОДНИМ запросом найти первый (в порядке возрастания) пропущенный номер и использовать его (причем так, чтобы другой пользователь в этот момент не успел подхватить тот же номер).
Спасибо!
1 alkorolev
 
17.04.13
05:46
префикс в коде есть?
2 golden-pack
 
17.04.13
05:46
1. Как можно (и можно ли) ОДНИМ запросом найти первый (в порядке возрастания) пропущенный номер и использовать его
- ответь на вопрос - как можно найти не запросом
2.(причем так, чтобы другой пользователь в этот момент не успел подхватить тот же номер). - никак
3 IamAlexy
 
17.04.13
05:52
(2) сам такой херней не маялся но чисто в теории:

1. предварительно заполнить таблицу значений из номеров затем скормить ее запросу присоеденив объекты по номеру и выбрав первую позицию с отсутствующим объектом

2. заблокировать на время всего этого действа объект типа блокировками типа управляемыми.
4 alkorolev
 
17.04.13
05:52
Если префикса нет, то что-то типа этого:
получаешь последний код справочника, преобразуешь его в число. Затем:
Для к = 1 по ПоследнийКод
КодСтрока = Формат(к, "ЧЦ=9; ЧВН=; ЧГ=");
НайденныйЭлемент = Справочники.ТвойСправочник.НайтиПоКоду(КодСтрока);
Если НайденныйЭлемент.Пустая() Тогда
// код свободен
...
5 alkorolev
 
17.04.13
05:53
в Формат(к, "ЧЦ=9; ЧВН=; ЧГ=") ты преобразуешь число обратно в код. ЧЦ=9 - допустимая длина кода, ЧВН - вы вод лидирующих нулей, ЧГ - без групппировок. Т.е. число 1 представляешь в виде "000000001"
6 cry_san
 
17.04.13
06:20
(1) Префикса нет - только ведущие нули
7 cry_san
 
17.04.13
06:21
(4) НайтиПоКоду в цикле не сильно будет тормозить программу?
8 cry_san
 
17.04.13
06:22
(2) Можно. Ответ почти такой же как и в (4)
9 Evpatiy
 
17.04.13
06:29
Ну на вскидку можно просто объединить таблицу номеров саму с собой и найти те номера для которых в Таблица2 нет номера равного Таблица1.Номер+1. Отсортировать их в порядке возрастания и выбрать первый. Чтобы другой пользователь не влез просто блокируй таблицу.
10 Evpatiy
 
17.04.13
06:30
(7) Запрос в данном случае скорее всего будет предпочтительнее.
11 Evpatiy
 
17.04.13
06:30
+(10) С точки зрения производительности
12 cry_san
 
17.04.13
06:30
(10) Ну так это понятно, но как это сделать запросом?
13 Evpatiy
 
17.04.13
06:31
(12) В 9 написал вариант.
14 cry_san
 
17.04.13
06:34
Сделал так:
   Запрос = Новый Запрос;
   Запрос.Текст = "
   |ВЫБРАТЬ ПЕРВЫЕ 1
   |    Код
   |ИЗ
   |    Справочник.Реестр
   |УПОРЯДОЧИТЬ ПО
   |    Код УБЫВ";
   
   Выборка = Запрос.Выполнить().Выбрать();
   Если Выборка.Следующий() Тогда
       ПоследнийКод = Выборка.Код;
   КонецЕсли;
   Сообщить(ПоследнийКод);
   
   Для к = 1 по Число(ПоследнийКод) Цикл
       КодСтрока = Формат(к, "ЧЦ=6; ЧВН=; ЧГ=");
       Сообщить("КодСтрока = " + Строка(КодСтрока));
       НайденныйЭлемент = Справочники.Реестр.НайтиПоКоду(КодСтрока);
       Если НайденныйЭлемент.Пустая() Тогда
           Сообщить(НайденныйЭлемент.Ссылка.Код);
       КонецЕсли;
   КонецЦикла;

Но не выводит код
15 Галахад
 
гуру
17.04.13
06:35
Гм, а как это  Таблица1.Номер+1  сработает при строковых дынных как у ТС?
16 Галахад
 
гуру
17.04.13
06:36
(14) Вариант (3) получше.
17 cry_san
 
17.04.13
06:39
(16) Согласен. Но пока не хватает теорзнаний для создания подобного ((
18 cry_san
 
17.04.13
06:43
(14) Поправил на
   Для к = 1 по Число(ПоследнийКод) Цикл
       КодСтрока = Формат(к, "ЧЦ=6; ЧВН=; ЧГ=");
       Сообщить("КодСтрока = " + Строка(КодСтрока));
       НайденныйЭлемент = Справочники.КПК_РеестрПайщиков.НайтиПоКоду(КодСтрока);
       Если НайденныйЭлемент.Пустая() Тогда
           Сообщить(КодСтрока);
       КонецЕсли;
   КонецЦикла;


Однако, если последнее число за 10000 - сильные тормоза - ждет пока переберет до последнего, если пропущенный номер 9999
19 Evpatiy
 
17.04.13
06:47
(15) У ТС нет префиксов, можно преобразовать в запросе в число.
20 Галахад
 
гуру
17.04.13
06:48
(19) Подскажи как строку преобразовать в число.
21 cry_san
 
17.04.13
06:48
(20) Число();
22 Галахад
 
гуру
17.04.13
06:48
(21) В запросе?
23 cry_san
 
17.04.13
06:51
ВЫБРАТЬ
   10/3 ВЫРАЗИТЬ КАК ЧИСЛО(15,2) КАК Цена
24 cry_san
 
17.04.13
06:52
25 Галахад
 
гуру
17.04.13
06:54
(23) Ага. А так:

ВЫБРАТЬ
  "10" ВЫРАЗИТЬ КАК ЧИСЛО(15,2) КАК Цена
26 1Сергей
 
17.04.13
06:54
(24) по твоей ссылке большое предупреждение:
"В запросах 1С с помощью функции ВЫРАЗИТЬ преобразовать строку в число нельзя"
27 Галахад
 
гуру
17.04.13
06:55
(24) А, ты уже понял.
28 cry_san
 
17.04.13
06:56
(27) Угу. Вернемся к (3). Практические идеи есть?
29 IamAlexy
 
17.04.13
06:58
(28) практическая идея: сесть и сделать..

каждый шаг моего гениального зловещего плана более чем реален.
что именно вас смущает в идее?
30 IamAlexy
 
17.04.13
06:59
да на фейхоа что либо куда преобразовывать?

сделайте генератором номера в том же формате в котором они есть.
заполните в базу и объеденяйте по номеру..

префикс?
текст?
да пофиг....
31 Evpatiy
 
17.04.13
06:59
(20) Вытащить в таблицу значений и преобразовать, вернуть в запрос.
32 1Сергей
 
17.04.13
06:59
(29) >>предварительно заполнить таблицу значений из номеров...
Перебор справочника будет быстрее
33 Галахад
 
гуру
17.04.13
06:59
(28) Ну вроде там описано.

1. Таблица
0001
0002
...
0N
2. К ней левым соединением таблицу номеров.
3. Где номер = null это и есть пропуски.
34 IamAlexy
 
17.04.13
07:01
(32) да что вы говорите...
35 cry_san
 
17.04.13
07:04
(32) Забил последним 25000. Пустой сделал 24999. Сижу уже 6 минут.
36 NWsFF
 
17.04.13
07:08
(9) Идея на столько хороша, что я бы поменяль тип кода на число.
37 IamAlexy
 
17.04.13
07:12
(35) сделай как с календарем..
регистр сведений с миллионом записей :)
и к нему цепляй  запросом :) :)
38 cry_san
 
17.04.13
07:13
(37) Ага, ждите )))
39 IamAlexy
 
17.04.13
07:15
(38) а кстати это вариант...

один раз заполнил регистр сведений "зарезервированныеномера" и далее запросом просто получаешь свободный номер.

если эта операция частая - в итоге будет экономия...
40 kosts
 
17.04.13
07:17
Перевод строки в число, при условии, что номера строго в формате "00001" (иначе еще в правильный формат нужно перевести)


Выбрать "0" как ЦифраСтрока, 0 как Цифра Поместить Цифры объединить все "1", 1 ...
Выбрать ... + ЕстьNULL(Цифры.Цифра*10, 0) + ЕстьNULL(Цифры.Цифра,0) как НомерЧисло
Левое соединение Цифры Как Единицы По Подстрока(Номера.Номер, 9, 1) = Цифры.ЦифраСтрока
Левое соединение Цифры Как Десятки По Подстрока(Номера.Номер, 8, 1) = Цифры.ЦифраСтрока
...


Хотя ноль можно совсем выкинуть...
41 IamAlexy
 
17.04.13
07:18
(40)  номера допустим с префиксами...
42 cry_san
 
17.04.13
07:19
(41) В конкретной задаче без префиксов
43 cry_san
 
17.04.13
07:20
(39) Интересный вариант. Операция частая.
"далее запросом просто получаешь СВОБОДНЫЙ номер" - пример можно?
44 kosts
 
17.04.13
07:22
(43) Нужно устранить причину появления дырок в нумерации - запретить запись не по порядку
45 IamAlexy
 
17.04.13
07:26
(43) естьnull(номенклатура.номер,0)
затем сортировка по возрастанию и выбор первого значения.
46 kosts
 
17.04.13
07:27
(43) >Частая операция
Это сколько раз в сутки? Если не тысячи, то нет смысла создавать регистр
47 IamAlexy
 
17.04.13
07:28
ну или чтобы текстовые номера сожрать:

выбор когда номенклатура.номер есть null тогда истина
иначе
ложь
конец

и далее сортировка  и выбор первого (ну или последнего) - не помню чо там первее отсортируется...
48 IamAlexy
 
17.04.13
07:28
(46) да там пофиг..
если частая - то регистр
если редкая - то заполняем таблицу значений номерами,передаем запрос и к ней цепляемся слева...
49 IamAlexy
 
17.04.13
07:29
это я к тому что не надо усложнять.. делать 100этажные запросы по преобразованию строк в числа и только ради того чтобы через месяц упереться в то что некий гений ввел номер типа 0001000/1 и вся нумерация накрылась раком
50 kosts
 
17.04.13
07:30
Если добавлять что-то в базу, то тогда лучше в этот же справочник добавить числовой реквизит и заполнять его при записи. Запросы по нему делать.
51 cry_san
 
17.04.13
07:31
(46) 10-100 раз
52 kosts
 
17.04.13
07:31
(49) Тем же раком накроется и регистр. Гадать можно долго. Пусть ТС решит для себя что ему проще...
53 kosts
 
17.04.13
07:33
(51) Ну тогда я бы не стал базу менять.
54 cry_san
 
17.04.13
07:33
(53) Послушаюсь вас.
55 IamAlexy
 
17.04.13
07:34
(52) в том то и прикол - не накроется...

подумай чуть то..

база увидит что есть свободный номер и назначит его.. то есть пользовательская корявка со слешами будет проигнорирована и нумерация не уйдет в ступор при достижении .../9
56 kosts
 
17.04.13
07:40
(55) Так же в запрос можно добавить одно условие и все не подходящие номера выпадут из выборки и ничего не упадет.
Не Номер Подобно "%[^0-9]%"
57 Лирик
 
17.04.13
07:42
Для числового кода я бы сделал так:
58 Лирик
 
17.04.13
07:42
Запрос = Новый Запрос;
   Запрос.Текст =
   "ВЫБРАТЬ
   |    ПробныйСправочник.Код,
   |    ПробныйСправочник.Код + 1 КАК Код1
   |ПОМЕСТИТЬ ТаблицаКодов
   |ИЗ
   |    Справочник.ПробныйСправочник КАК ПробныйСправочник
   |;
   |
   |////////////////////////////////////////////////////////////////////////////////
   |ВЫБРАТЬ
   |    МИНИМУМ(ТаблицаКодов1.Код1) КАК Код1
   |ИЗ
   |    ТаблицаКодов КАК ТаблицаКодов1
   |        ЛЕВОЕ СОЕДИНЕНИЕ ТаблицаКодов КАК ТаблицаКодов
   |        ПО ТаблицаКодов1.Код1 = ТаблицаКодов.Код
   |ГДЕ
   |    ТаблицаКодов.Код ЕСТЬ NULL ";
   
   Рез = Запрос.Выполнить().Выбрать();
   Рез.Следующий();
   
   ПропущенныйКод = Рез.Код1;
59 kosts
 
17.04.13
07:44
(58) +1 Можно в одной выборке все сделать.
60 IamAlexy
 
17.04.13
07:49
(58) смоделируй работу запроса при пропуске 5ти номеров...
61 Лирик
 
17.04.13
07:52
(60) И что?
62 cry_san
 
17.04.13
07:54
(58) (60) Все прекрасно работает!!
И мне понравилось ваше простое решение. :)
63 IamAlexy
 
17.04.13
07:55
(61)

у вас в справочнике заняты номера 1,2,3,10,11,12

сработает запрос ?
64 cry_san
 
17.04.13
07:56
(63) Да. Выводит 4
65 IamAlexy
 
17.04.13
07:56
а хотя да, сработает
66 IamAlexy
 
17.04.13
07:57
клевое решение для числовых кодов
67 cry_san
 
17.04.13
07:59
Еще один момент. Пользователь создает элемент в справочнике. Номер проставляем один из пустых. Как не дать в этот момент использовать другому пользователю этот же код. Ведь элемент справочника до сих пор ведь не создан.
68 kosts
 
17.04.13
08:00
(67) Получай и записывай номер в момент записи в БД. (как в типовых)
69 cry_san
 
17.04.13
08:00
(68) А если в этот момент коллизия?
70 kosts
 
17.04.13
08:03
(70) Ну не знаю, проверяй существование такого номера и отказ.
71 cry_san
 
17.04.13
08:05
(70) Ok!
72 cry_san
 
17.04.13
08:05
Все большое СПАСИБО!
73 NWsFF
 
17.04.13
09:29
То что было сказано в 9 посте, поняли только к 72. Вах, вах, какие невнимательные.
74 Serg_1960
 
17.04.13
09:58
"Не учите меня жить(9), лучше помогите материально(58)"(с)
75 Лефмихалыч
 
17.04.13
10:06
(0) вот тебе три номера:

01-вася
-петя
02-12

сколько между ними пропущенных?
76 cry_san
 
17.04.13
10:26
(75) Смотрите ответ тут (66)
77 Advan
 
17.04.13
10:49
(58)Класс - правда проблема если код хоть и цифрами, но в формате строковом. Выразить в запросе не переведет строку в число :(
А так был бы мой случай у клиентов - в цикле перебирать долго - думаю придется регистр бацать.
Есть два вида языков, одни постоянно ругают, а вторыми никто не пользуется.