Имя: Пароль:
1C
1C 7.7
v7: Пресловутая перенумерация справочника...
0 MWWRuza
 
гуру
03.03.17
22:14
Я как-бы привык, что коды в справочниках чаще всего текстовые... Но, возникла задача, справочник с числовым кодом. Казалось бы, задача простейшая... Но, то-ли я заработался совсем, и не вижу какую-то свою ошибку, то-ли есть какой-то баг(фича?) ядра...
Алгоритм такой - Создаю ТЗ, с двумя колонками, "Код", и сам элемент справочника "Эл". Заполняю ее выборкой по справочнику, в ПорядокКодов().
Создаю, для чистоты эксперимента, отдельный справочник "Спр2".
Дальше, бегу в цикле Для Сч = 1 по ТЗ.КоличествоСтрок() по таблице.
Ищу в ТЗ по колонке "Код" значение счетчика(Сч). Если не нахожу(свободный код!) - то получаю значение из ТЗ по номеру строки(Сч) и колонке "Эл", после чего, ищу этот элемент в Спр2 и устанавливаю атрибут "Код" для этого элемента равный "Сч". Записываю.
Казалось бы, все правильно... Но, получаю эффект, как при прямом удалении элемена из выборки, когда нарушается сама выборка... С каждым запуском обработки, перенумеровывается несколько элементов, а дальше не работает... Не пойму, где теряется выборка...
Вот весь текст обработки:
Процедура Сформировать()
    Спр = СоздатьОбъект("Справочник.Номенклатура");
    ТЗ     = СоздатьОбъект("ТаблицаЗначений");
    ТЗ.НоваяКолонка("Код","Число");
    ТЗ.НоваяКолонка("Эл");
    Спр.ПорядокКодов();
    Спр.ВыбратьЭлементы(0);
    Сч = 0;
    Пока Спр.ПолучитьЭлемент() = 1 Цикл
        Сч = Сч + 1;
        ТЗ.НоваяСтрока();
        ТЗ.Код         = Число(Спр.Код);
        ТЗ.Элемент    = Спр.ТекущийЭлемент();
    КонецЦикла;
    Спр2 = СоздатьОбъект("Справочник.Номенклатура");
    ТЗ.Сортировать("Код");
    Сч = 0;
    Для Сч = 1 По ТЗ.КоличествоСтрок() Цикл
        Стр = "";
        Если ТЗ.НайтиЗначение(Сч,Стр,"Код") = 0 Тогда
            ТекЭл    = ТЗ.ПолучитьЗначение(Сч,"Эл");
            Если Спр2.НайтиЭлемент(ТекЭл) = 1 Тогда
                Спр2.УстановитьАтрибут("Код",Сч);
                Спр2.Записать();
                Состояние("Обработано " + Сч);
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    Сообщить("Всего элементов " + Сч);
КонецПроцедуры
1 Garykom
 
гуру
03.03.17
22:17
гы "Спр.ВыбратьЭлементы(0);"

Глянь нумерация не в пределах подчинения случаем?
2 Garykom
 
гуру
03.03.17
22:20
Да вот это:

    Для Сч = 1 По ТЗ.КоличествоСтрок() Цикл
        Стр = "";
        Если ТЗ.НайтиЗначение(Сч,Стр,"Код") = 0 Тогда
            ТекЭл    = ТЗ.ПолучитьЗначение(Сч,"Эл");
            Если Спр2.НайтиЭлемент(ТекЭл) = 1 Тогда
                Спр2.УстановитьАтрибут("Код",Сч);
                Спр2.Записать();
                Состояние("Обработано " + Сч);
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;

полная тормозная хре

Все проще, переименование в два этапа - полных прохода.

Сначала нумеруем все элементы (допустим максимальный номер 10 000) по порядку 10 001, 10 002, ...

А затем как нуна 1,2,3 и т.д. на втором проходе
3 mehfk
 
03.03.17
22:21
А учёйсом никак?
4 MWWRuza
 
гуру
03.03.17
22:30
1. Справочник не подчиненный.
2. Я никуда не спешу, и понимаю, что с точки зрения производительности, это не оптимально... Но, на это есть свои причины... Если код в пределах общего количества элементов, то хотелось бы оставить его на месте(привязка внутренних ШК к коду), и только те, которые за пределами количества элементов, перенумеровать, "всунов" в пустые места.
3. "А учёйсом никак?" - не понял...
5 Garykom
 
гуру
03.03.17
22:32
(4) Тогда точно не то делаешь если хочешь "всунуть".

Тебе просто нужны 2 списка:
1. Список пустых номеров
2. Список выходящих за пределы элементов

Далее нумеруешь 2-й список подряд номерами из 1-го, один уй 2 прохода
6 Garykom
 
гуру
03.03.17
22:42
(5)+ самый быстрый способ получить "список пустых" это массив заполняем где куда по номеру пишем 1, а по умолчанию 0.
Далее проход по массиву и вот значения с 0 пустые. Можно и через ТЗ в 2 колонки.
7 Garykom
 
гуру
03.03.17
22:42
(6)+ хотя нафик 2 колонки в ТЗ, там же нумерация есть = массив
8 mehfk
 
03.03.17
22:44
9 MWWRuza
 
гуру
03.03.17
22:45
Да, все верно...
Но, сбой в нумерации пошел недавно, и по большому счету, мне наплевать на ихние проблемы, возникшие после сбоя... Поэтому, я и решил начать перенумеровывать сквозняком, с момента возникновения сбоя. Не нашли в ТЗ код, присваиваем текущему элементу(полученному из тз по порядку) новый, который по порядку, свободный(мы же его не нашли в ТЗ, значит он свободный). Далее, если попадается код, который совпадает со Сч, пропускаем, ничего с ним не делая, пусть он остается на своем месте.
10 Garykom
 
гуру
03.03.17
22:56
(9) Научитесь правильно выделять отдельные блоки-подпрограммы в алгоритме и оформлять их в виде отдельных процедур/функций.

Будет проще/быстрее программировать и меньше икать придется когда ваш код кто то другой увидит:

Функция ПереименоватьЭлемент(Элемент, НовыйНомер)
   Элемент.УстановитьАтрибут("Код", НовыйНомер);
   Элемент.Записать();
КонецФункции

и т.д.
11 MWWRuza
 
гуру
03.03.17
22:58
Ок. Правильно, сейчас перепишу... Просто, обработка - детский сад, поэтому не стал сразу так делать.
12 MWWRuza
 
гуру
03.03.17
23:06
Процедура ИзменитьКод(ТЗ,Сч)
    Спр = СоздатьОбъект("Справочник.Номенклатура");
    ТекЭл    = ТЗ.ПолучитьЗначение(Сч,"Эл");
    Если Спр.НайтиЭлемент(ТекЭл) = 1 Тогда
        Спр.УстановитьАтрибут("Код",Сч);
        Спр.Записать();
        Состояние("Обработано " + Сч);
    КонецЕсли;    
КонецПроцедуры    

Процедура Сформировать()
    Спр = СоздатьОбъект("Справочник.Номенклатура");
    ТЗ     = СоздатьОбъект("ТаблицаЗначений");
    ТЗ.НоваяКолонка("Код","Число");
    ТЗ.НоваяКолонка("Эл");
    Спр.ПорядокКодов();
    Спр.ВыбратьЭлементы(0);
    Сч = 0;
    Пока Спр.ПолучитьЭлемент() = 1 Цикл
        Сч = Сч + 1;
        ТЗ.НоваяСтрока();
        ТЗ.Код         = Число(Спр.Код);
        ТЗ.Эл    = Спр.ТекущийЭлемент();
    КонецЦикла;
    ТЗ.Сортировать("Код");
    Сч = 0;
    Для Сч = 1 По ТЗ.КоличествоСтрок() Цикл
        Стр = "";
        Если ТЗ.НайтиЗначение(Сч,Стр,"Код") = 0 Тогда
            ИзменитьКод(ТЗ,Сч);
        КонецЕсли;
    КонецЦикла;
    Сообщить("Всего элементов " + Сч);
КонецПроцедуры
13 MWWRuza
 
гуру
03.03.17
23:14
Прокоментировал:
Процедура ИзменитьКод(ТЗ,Сч)
    Спр = СоздатьОбъект("Справочник.Номенклатура");
    ТекЭл    = ТЗ.ПолучитьЗначение(Сч,"Эл");
    Если Спр.НайтиЭлемент(ТекЭл) = 1 Тогда
        Спр.УстановитьАтрибут("Код",Сч);
        Спр.Записать();
        Состояние("Обработано " + Сч);
    КонецЕсли;    
КонецПроцедуры    

Процедура Сформировать()
    Спр = СоздатьОбъект("Справочник.Номенклатура");
    ТЗ     = СоздатьОбъект("ТаблицаЗначений");
    ТЗ.НоваяКолонка("Код","Число");
    ТЗ.НоваяКолонка("Эл");
    Спр.ПорядокКодов();
    Спр.ВыбратьЭлементы(0);
    Сч = 0;
    Пока Спр.ПолучитьЭлемент() = 1 Цикл
        Сч = Сч + 1;
        ТЗ.НоваяСтрока();
        ТЗ.Код         = Число(Спр.Код);
        ТЗ.Эл    = Спр.ТекущийЭлемент();
    КонецЦикла; // Заполнили, тут все ОК.
    ТЗ.Сортировать("Код");  // На всякий случай - танцы с бубном(ТБ)
    Сч = 0;
    Для Сч = 1 По ТЗ.КоличествоСтрок() Цикл
        Стр = "";
        Если ТЗ.НайтиЗначение(Сч,Стр,"Код") = 0 Тогда  // Не нашли, код сбободный, следующему элементу можно его присвоить
            ИзменитьКод(ТЗ,Сч);
        КонецЕсли;
    КонецЦикла;
    Сообщить("Всего элементов " + Сч);
КонецПроцедуры
14 vova1122
 
06.03.17
17:17
Когда-то давно сделал для себя такую обработку. Товары с кодом большим от заданного расставляю в пустые места. Если товара больше чем пустых мест, то переместятся только с те у которых наибольшей номер.
Если актуально, могу поделится.
15 Злопчинский
 
06.03.17
18:01
возьмите уже наконец набор универсальных отчетов и обработок с диска ИТС
16 vova1122
 
06.03.17
18:28
(15) какраз ту задачу что нужно автору, и когда-то было нужно мне не выполняет ни одна из обработок из ИТС
17 Злопчинский
 
06.03.17
18:54
(16) что? пернумеровать элементы справочника, чтобы коды шли по порядку?
18 vova1122
 
06.03.17
19:01
(17) прочтите внимательно
19 Ёпрст
 
06.03.17
19:03
(13) зачетная трава
20 Ёпрст
 
06.03.17
19:10
Если че, ты своим поиском счетчик цикла сбиваешь нахрен :)
Почитай на досуге, как работает метод НайтиЗначение и что он возвращает в параметры метода.
21 Ёпрст
 
06.03.17
19:10
и.. больше так не делай.
22 vova1122
 
06.03.17
19:26
(17) Для старых товаров с небольшим номером оставить те же номера. Их не перенумеровывать.
А товары которые недавно созданы (с большим номером) перенумеровать - присвоить новый номер(из пропущенных номеров)
23 Злопчинский
 
06.03.17
22:48
(22) такая задача имеет смысл только в том случае если в код элемента справочника - который для тупой нумерации и все - вкладывать дополнительные смыслы
24 Злопчинский
 
06.03.17
22:49
(22) фигня полная
Ибо нет критерия что такое старый и новый товары
25 Злопчинский
 
06.03.17
22:52
(22) тупой шаблонтпишется на коленке
Получаем список неиспользуемых номеров
И в движении по обратной выборке используем их
Неинтересно
26 MWWRuza
 
гуру
07.03.17
01:28
Сделал я еще в тот-же день, вот так, ищу не в ТЗ а сразу в справочнике, так отрабатывает нормально:

Процедура Сформировать()
    Спр = СоздатьОбъект("Справочник.Номенклатура");
    ТЗ     = СоздатьОбъект("ТаблицаЗначений");
    ТЗ.НоваяКолонка("Код","Число");
    ТЗ.НоваяКолонка("Эл");
    Спр.ПорядокКодов();
    Спр.ВыбратьЭлементы(0);
    Сч = 0;
    Пока Спр.ПолучитьЭлемент() = 1 Цикл
        Сч = Сч + 1;
        ТЗ.НоваяСтрока();
        ТЗ.Код         = Число(Спр.Код);
        ТЗ.Эл    = Спр.ТекущийЭлемент();
    КонецЦикла; // Заполнили, тут все ОК.
    ТЗ2 = СоздатьОбъект("ТаблицаЗначений");
    ТЗ.Выгрузить(ТЗ2);
    ТЗ.Сортировать("Код");  // На всякий случай - танцы с бубном(ТБ)
    НачатьТранзакцию();
    Сч = 0;
    ТЗ.ВыбратьСтроки();
    Сч = 0;
    Сч2 = 0;
    Пока ТЗ.ПолучитьСтроку() = 1 Цикл
        Сч = Сч + 1;
        Стр = "";
        Если Спр.НайтиПоКоду(Сч) = 0 Тогда
            Если Спр.НайтиЭлемент(ТЗ.ПолучитьЗначение(Сч,"Эл")) =1 Тогда
                Спр.УстановитьАтрибут("Код",Сч);
                Спр.Записать();
                Если Сч%500 = 0 Тогда
                    Состояние("Обработано " + Сч);
                    ЗафиксироватьТранзакцию();
                    НачатьТранзакцию();
                КонецЕсли;    
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;                        
    ЗафиксироватьТранзакцию();
    Сообщить("Всего элементов " + Сч);
КонецПроцедуры

Да, все таки видимо в этом дело: "Если че, ты своим поиском счетчик цикла сбиваешь нахрен :) "
27 MWWRuza
 
гуру
07.03.17
01:48
"как работает метод НайтиЗначение и что он возвращает в параметры метода"
Ну... И что?

Параметры:
<Знач> - значение для поиска.
<Строка> - идентификатор переменной, куда возвращается номер найденной строки. Если при вызове метода передать в этот параметр номер строки, то поиск будет осуществляться только по указанной строке.
<Колонка> - номер или идентификатор колонки, возвращает номер найденной колонки. Идентификатор переменной, куда возвращается номер найденной колонки. Если при вызове метода передать в этот параметр номер или идентификатор колонки, то поиск будет осуществляться только по указанной колонке.

Цикл по ТЗ у меня принудительный, не выборкой "Пока получить", а просто по счетчику от 1 до КоличествоСтрок(), на каждом шаге цикла я параметр поиска, перед поиском, делаю пустым - Стр = "". Какое отношение найденный или не найденный номер строки имеет к циклу? Объясните бестолковому плиз, не ради прикладной задачи, ее я решил по другому, а на будущее...
28 MWWRuza
 
гуру
07.03.17
02:00
"такая задача имеет смысл только в том случае если в код элемента справочника - который для тупой нумерации и все - вкладывать дополнительные смыслы"

Именно так. К кодам справочника привязаны ШК весового товара, а так же просто внутренние ШК. Их хоть и не много, но встречаются. По этому и была задача, по возможности оставить все на своих местах, и перенумеровать только явные "косяки", те элементы, код которых больше чем количество элементов в справочнике.

PS Если че - я не курю, не только траву, а даже сигареты:)))
29 vova1122
 
07.03.17
09:47
(26) мне кажется вы не добились того что хотели. По этому алгоритму будет не заполнение пропущенных номеров, а тупо уплотнение списка.
Для ясности пример.
У вас было:
1. Товар1
4. Товар4
5. Товар5
8. Товар8
10. Товар10

А попучилось:
1. Товар1
2. Товар4
3. Товар5
4. Товар8
5. Товар10

Такого результата вы хотели?
Или может такого:
1. Товар1
2. Товар8
3. Товар10
4. Товар4
5. Товар5
30 Злопчинский
 
07.03.17
10:27
Думаю в рамках задачи автора - одновалентно
31 MWWRuza
 
гуру
08.03.17
21:40
Ну, да... Задача решена, полностью. По логике задачи, именно такое "уплотнение" полностью решает все проблемы.
Но, как в том анекдоте - "Ложечки то нашлись, но осадочек остался!"...
Так и не понял, где в первоначальном алгоритме ошибка:(
32 MWWRuza
 
гуру
08.03.17
22:08
Наверно в ДНК :(
33 vova1122
 
09.03.17
10:54
(31) Ты создал один раз таблицу значений. И в процессе переименовании кодов данные в таблице значений не изменяются.
Например в таблице значений нет товара с кодом 10. Дальше ты присвоил номер 10 товару который до этого имел  номер 11.
Получается, что в базе уже нет товара с кодом 11, а в таблице значений он есть. Получается нестыковка.....
На следующем шаге когда ищешь в таблице значений товар с кодом 11, обработка его пропускает, так как в он есть в ТЗ. А в базе то его нет!!!! (ты его переименовал на номер 10 на предыдущем щаге)!!!!!
34 MWWRuza
 
гуру
09.03.17
21:57
Точно...
Спасибо!
Заработался я совсем, такую очевидную вещь не заметил...