Имя: Пароль:
1C
1С v8
Запрос всех строк номенклатуры из всех табличных частей всех документов
0 fazendoid
 
16.01.13
16:38
Добрый день, есть задача, моск уже не варит. Нужно:
1. Взять все документы (ну это ясно, метаданные конфы).
2. Вытащить их табличные части (тут метаданные доков),
3. в которых есть строки с номенклатурой (Товары, Услуги, Материалы и т.п. — не ясно)
4. Сочленить эту номенклатуру в один список (объединяем).
5 (не обязательный). Пометить номенклатуру, отсутствующую в списке из пункта 4 на удаление.

Вот по отдельности всё вроде как ясно, а сочленить в рабочее решение не получается.
Никто не сталкивался с таким? Или, может, я вообще велосипед изобретаю?
1 ДенисЧ
 
16.01.13
16:39
НайтиПоСсылкам()
:-)
2 lefthander
 
16.01.13
16:39
Может надо пометить не используемую номенклатуру на удаление?
3 Нуф-Нуф
 
16.01.13
16:40
получить массив всей номенклатуры, получить на них ссылки, отобрать с ссылками в документах. остальные удалить
4 fazendoid
 
16.01.13
16:51
(1) Едрать... Всё, вопрос отпал :) Огромное спасибо, вы предотвратили появление очередного веломобиля))
5 vtolga
 
16.01.13
16:57
Только Доолго будет...
6 Нуф-Нуф
 
16.01.13
16:57
(5) долго понятие растяжимое и относительное
7 vtolga
 
16.01.13
16:58
Модет, вместо документов обороты по каким-нибудь регистрам проанализируешь?
8 fazendoid
 
16.01.13
22:37
(7) Да я думаю, что мозголомки с этим не меньше будет
9 fazendoid
 
17.01.13
09:08
В общем, такая шняга получилась :) :

Итерация = 0;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Таблицы.Номенклатура ИЗ (
   |";
Для Каждого Документ Из Метаданные.Документы Цикл
   
       //Сообщить("---------------------------
       //|Документ: "+Документ.Имя);
   Для Каждого ТабличнаяЧасть Из Документ.ТабличныеЧасти Цикл
       //Сообщить("ТабличнаяЧасть: "+ТабличнаяЧасть.Имя);
       Для Каждого Реквизит Из ТабличнаяЧасть.Реквизиты Цикл
           //Сообщить("Реквизит: "+Реквизит.Имя);
           Если Реквизит.Имя = "Номенклатура" Тогда
               //Сообщить("------- Хоп");
               Если Итерация = 1 Тогда
                   Запрос.Текст = Запрос.Текст + "
                       |
                       |ОБЪЕДИНИТЬ
                       |";
               КонецЕсли;
               Запрос.Текст = Запрос.Текст + "
                   |ВЫБРАТЬ ТЧ.Номенклатура КАК Номенклатура
                   |ИЗ Документ." +Документ.Имя+ "." +ТабличнаяЧасть.Имя+ " КАК ТЧ
                   |ГДЕ ТЧ.Номенклатура ССЫЛКА Справочник.Номенклатура";
               //Сообщить(Запрос.Текст);
               Итерация = ?(Итерация = 0,1,1);
           КонецЕсли;
           
       КонецЦикла;
   КонецЦикла;
КонецЦикла;
Запрос.Текст = Запрос.Текст + "
   |) КАК Таблицы
   |УПОРЯДОЧИТЬ ПО Таблицы.Номенклатура";
Сообщить(Запрос.Текст);
ТаблицаЗначений = Запрос.Выполнить().Выгрузить();
Для Каждого Строка Из ТаблицаЗначений Цикл
   Сообщить(Строка.Номенклатура);
КонецЦикла;
Сообщить(ТаблицаЗначений.Количество());
10 fazendoid
 
17.01.13
09:09
(9) Тьфу, дебажные сообщения забыл удалить :). И у меня такое ощущение, что строк маловато выводит(
11 Defender aka LINN
 
17.01.13
09:19
Дебажные сообщения, my ass... Про отладку не слышали, не?
12 КуплюКровать
 
17.01.13
09:23
пометь на удаление всю номенклатуру, запусти удаление помеченых, потом сними пометку. Че удалится - то без ссылок было. Одна проблема, нужно сохранить пометки удаления, которые были до проведения этой операции. Но это, думаю догадаешься как
13 fazendoid
 
17.01.13
09:32
(11) Да я это пишу и запускаю в микроредакторе в клиентском режиме — так побыстрее и попроще получается. И что-то у меня не получается подцепить отладчик на внешнюю обработку. ЧЯДНТ?
14 fazendoid
 
17.01.13
09:38

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


Только не пойму, почему список не упорядочивается?
15 fazendoid
 
17.01.13
09:41
(12) Да это в первую очередь нужно для человека, который шерстит номенклатуру на предмет неиспользуемости — вывести ему отчет, какая нома где используется. А удаление — это уже полезная хфича
16 mxs089
 
17.01.13
09:41
(14) |УПОРЯДОЧИТЬ ПО Таблицы.Номенклатура.Наименование
17 fazendoid
 
17.01.13
09:44
(16) Спасибо, сам бы не додумался. По ссылкам типа не сортирует?
18 Jstunner
 
17.01.13
09:46
(17) сортирует. По индентификатору ссылки
19 Reset
 
17.01.13
09:48
Что-то я не понял... Вроде и ответ дали (1) и автор ему обрадовался(4), а таки прет по старому пути :???:
20 fazendoid
 
17.01.13
10:11
(19) Это из любопытства всё


Итерация = 0;
Запрос = Новый Запрос;
МВТ = Новый МенеджерВременныхТаблиц;
Запрос.МенеджерВременныхТаблиц = МВТ;
Запрос.Текст = "ВЫБРАТЬ Таблицы.Номенклатура ПОМЕСТИТЬ ВременнаяТаблица ИЗ (
   |";
Для Каждого Документ Из Метаданные.Документы Цикл
   
       //Сообщить("---------------------------
       //|Документ: "+Документ.Имя);
   Для Каждого ТабличнаяЧасть Из Документ.ТабличныеЧасти Цикл
       //Сообщить("ТабличнаяЧасть: "+ТабличнаяЧасть.Имя);
       Для Каждого Реквизит Из ТабличнаяЧасть.Реквизиты Цикл
           //Сообщить("Реквизит: "+Реквизит.Имя);
           Если Реквизит.Имя = "Номенклатура" Тогда
               //Сообщить("------- Хоп");
               Если Итерация = 1 Тогда
                   Запрос.Текст = Запрос.Текст + "
                       |
                       |ОБЪЕДИНИТЬ
                       |";
               КонецЕсли;
               Запрос.Текст = Запрос.Текст + "
                   |ВЫБРАТЬ ТЧ.Номенклатура КАК Номенклатура
                   |ИЗ Документ." +Документ.Имя+ "." +ТабличнаяЧасть.Имя+ " КАК ТЧ
                   |ГДЕ ТЧ.Номенклатура ССЫЛКА Справочник.Номенклатура";
               //Сообщить(Запрос.Текст);
               Итерация = ?(Итерация = 0,1,1);
           КонецЕсли;
           
       КонецЦикла;
   КонецЦикла;
КонецЦикла;
Запрос.Текст = Запрос.Текст + "
   |) КАК Таблицы
";
//Сообщить(Запрос.Текст);
ТаблицаЗначений = Запрос.Выполнить().Выгрузить();
//Для Каждого Строка Из ТаблицаЗначений Цикл
//    Сообщить(Строка(Строка.Номенклатура) + " — " + Строка(Строка.Документ));
//КонецЦикла;
//Сообщить(ТаблицаЗначений.Количество());
Запрос1 = Новый Запрос;
Запрос1.Текст = "
   |ВЫБРАТЬ Номенклатура.Ссылка
   |ИЗ Справочник.Номенклатура КАК Номенклатура
   |ГДЕ Номенклатура.Ссылка НЕ В (&ТЗ)
   |УПОРЯДОЧИТЬ ПО Номенклатура.Ссылка.Наименование";
Запрос1.УстановитьПараметр("ТЗ",ТаблицаЗначений);
ТаблицаЗначений1 = Запрос1.Выполнить().Выгрузить();
Для Каждого Строка Из ТаблицаЗначений1 Цикл
   Сообщить(Строка(Строка.Ссылка));
КонецЦикла;
Сообщить(ТаблицаЗначений1.Количество());

Как-то не как надо работает, в конечный список попадают-таки номенклатуры с документами.
21 Reset
 
17.01.13
10:20
Из любопытства, хм.
Тогда не забудь еще собрать всё из справочников, где номенклатура может в реквизитах быть и в табличных частях, в регистрах сведений (без регистратора особенно). Да и в регистрах накопления технически может быть, даже если в дркументах есть (напр документ КорректировкаЗаписей РегистровНакопрления без табл частей). Регистры бухгалтерии (бух операция может там оставить двежения).
22 Reset
 
17.01.13
10:20
читать "даже если в документах нет"
23 Reset
 
17.01.13
10:23
(20) Лень анализировать, бросилось в глаза
Если Реквизит.Имя = "Номенклатура" Тогда
Это неверно, проверять надо не по имени реквизита, а по типу.
24 fazendoid
 
17.01.13
11:22
(23)

Тип = Справочники.Номенклатура.НайтиПоКоду(1).Метаданные().Имя;

Если Строка(Реквизит.Тип) = Строка(Тип) Тогда


Явно ведь не так, да? Как правильно, не подскажите?
25 Reset
 
17.01.13
11:29
(24)
ТипНоменклатура=Тип("СправочникСсылка.Номенклатура");

...
Если Реквизит.Тип.СодержитТип(ТипНоменклатура)
26 fazendoid
 
17.01.13
11:41
(25) Спасибо :)
27 fazendoid
 
17.01.13
12:21
Теперь другой путь:

Запрос = Новый Запрос;
Запрос.Текст = "
   |ВЫБРАТЬ Ссылка
   |ИЗ Справочник.Номенклатура";
ВсяНоменклатура = Запрос.Выполнить().Выгрузить();
Сообщить(ВсяНоменклатура.Количество());

Массив = ВсяНоменклатура.ВыгрузитьКолонку("Ссылка");
СсылкиНоменклатуры = НайтиПоСсылкам(Массив);
Сообщить(СсылкиНоменклатуры.Количество());

Запрос0 = Новый Запрос;
МВТ = Новый МенеджерВременныхТаблиц;
Запрос0.МенеджерВременныхТаблиц = МВТ;

Запрос0.Текст = "
   |ВЫБРАТЬ * ПОМЕСТИТЬ ВТ
   |ИЗ &ТЗ КАК Ссылки";
Запрос0.УстановитьПараметр("ТЗ",СсылкиНоменклатуры);
Запрос0.Выполнить();
Запрос0.Текст = "
   |ВЫБРАТЬ ПЕРВЫЕ 100000 Номенклатура.Ссылка ПОМЕСТИТЬ ВТ
   |ИЗ Справочник.Номенклатура КАК Номенклатура
   |ГДЕ НЕ Номенклатура.Ссылка В ВТ
   |УПОРЯДОЧИТЬ ПО Номенклатура.Ссылка.Наименование";

Номенклатура = Запрос0.Выполнить().Выгрузить();
Сообщить(Номенклатура.Количество());

Для Каждого Строка Из Номенклатура Цикл
   Сообщить(Строка(Строка[0]));
   ОбработкаПрерыванияПользователя();
КонецЦикла;

МВТ.Закрыть();

И получаем:

Тип не может быть выбран в запросе
ИЗ <<?>>&ТЗ КАК Ссылки

У нас ведь таблица создается путем выгрузки результатов запроса, типы должны быть расставлены. Почему так?
28 DrShad
 
17.01.13
12:23
(27) какого запроса?
29 fazendoid
 
17.01.13
12:24
(28) Запрос0, там же только одна такая конструкция
30 Reset
 
17.01.13
12:25
(27) Она не может быть типозована, там разные типы в строках могут быть
31 Reset
 
17.01.13
12:26
типизована*
32 Reset
 
17.01.13
12:26
Создай свою тз с типизованной колонкой и перекай в нее ссылки.
33 Reset
 
17.01.13
12:27
перекачай*
что же этакое со мной
34 Reset
 
17.01.13
12:27
Следующая ошибка у тебя в строке

"ГДЕ НЕ Номенклатура.Ссылка В ВТ"
35 Reset
 
17.01.13
12:28
для "в" нужна выборка из ВТ
или вместо "в" соединение исполльзовать
36 Reset
 
17.01.13
12:30
"ПОМЕСТИТЬ ВТ" совсем лишнее во второй части запроса.
Короче все плохо :)
37 fazendoid
 
17.01.13
14:09
(36)

// Вывод Номенклатура - Ссылка на номенклатуру в объекте - Тип объекта

Запрос = Новый Запрос;
Запрос.Текст = "
   |ВЫБРАТЬ Ссылка
   |ИЗ Справочник.Номенклатура";
ВсяНоменклатура = Запрос.Выполнить().Выгрузить();

Массив = ВсяНоменклатура.ВыгрузитьКолонку("Ссылка");
СсылкиНоменклатуры = НайтиПоСсылкам(Массив);

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("НоменклатураСсылка", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));

МассивСсылок = СсылкиНоменклатуры.ВыгрузитьКолонку(0);
Сообщить(МассивСсылок.Количество());
Для Каждого Строка Из МассивСсылок Цикл
   ТЗ.Добавить();
КонецЦикла;
ТЗ.ЗагрузитьКолонку(МассивСсылок,ТЗ.Колонки["НоменклатураСсылка"]);
 
Запрос0 = Новый Запрос;
МВТ = Новый МенеджерВременныхТаблиц;
Запрос0.МенеджерВременныхТаблиц = МВТ;
Запрос0.Текст = "
   |ВЫБРАТЬ НоменклатураПоСсылкам.НоменклатураСсылка КАК НоменклатураСсылка
   |ПОМЕСТИТЬ ВременнаяТаблица
   |ИЗ &ТЗ КАК НоменклатураПоСсылкам
   |
   |;
   |
   |ВЫБРАТЬ ПЕРВЫЕ 100000 Номенклатура.Ссылка
   |ИЗ Справочник.Номенклатура КАК Номенклатура
   |ГДЕ НЕ Номенклатура.Ссылка В (ВЫБРАТЬ ВТ.НоменклатураСсылка ИЗ ВременнаяТаблица КАК ВТ)
   |УПОРЯДОЧИТЬ ПО Номенклатура.Ссылка.Наименование";
Запрос0.УстановитьПараметр("ТЗ",ТЗ);

Номенклатура = Запрос0.Выполнить().Выгрузить();
Сообщить(Номенклатура.Количество());

Для Каждого Строка Из Номенклатура Цикл
   Сообщить(Строка(Строка[0]));
   ОбработкаПрерыванияПользователя();
КонецЦикла;

МВТ.Закрыть();

Почему-то временная таблица у пустая :(
38 fazendoid
 
17.01.13
14:14
(37) ТЗ при этом заполнена
39 Reset
 
17.01.13
14:19
Как определил что пустая?
40 fazendoid
 
17.01.13
14:24
(39) Косвенно

Выбрать * Из ВременнаяТаблица
41 Reset
 
17.01.13
14:26
Если честно, для одноразовой обработки я вообще с запросом не заморачивался

СсылкиНоменклатуры.Индексы.Добавить("Ссылка");
Для каждого СтрНоменклатуры из ВсяНоменклатура цикл
 Если СсылкиНоменклатуры.Найти(СтрНоменклатуры.Ссылка,"Ссылка")=Неопределено тогда
  Сообщить(СтрНоменклатуры.Ссылка);
КонецЦикла;
42 fazendoid
 
17.01.13
14:32
(41) Я бы, наверное, тоже не заморачивался. Если бы умел это делать :) И если бы это не было частью самообучения.

Хм, Временная все-таки заполнена, я перепроверил.
43 Reset
 
17.01.13
14:32
(40) Как то странно, если ТЗ не пустая. Или я в упор не вижу какого-то косяка, хз, но на вид выборка в вт нормальная.

Можно добавить Выразить(), но моему, это не должно влиять.
ВЫБРАТЬ Выразить(НоменклатураПоСсылкам.НоменклатураСсылка Как Справочник.Номенклатура) КАК НоменклатураСсылка
44 Reset
 
17.01.13
14:32
(42) Ну блин :)
45 Maxus43
 
17.01.13
14:34
Проанализировать регистры то не предлагали?
46 Reset
 
17.01.13
14:34
(45) Предлагали :)
47 Reset
 
17.01.13
14:40
Вообще, если цель удалить все неиспользуемые, можно обойтись без обработок (ну почти) :)

1. Пометить на удаление ВСЕ.
2. С помощью платформенной "удаление помеченных объектов" удалить все что удастся.
3. Снять пометку у ВСЕХ.
48 fazendoid
 
17.01.13
14:47
(47) Это-то мне в голову и не пришло :)

А есть ли обработка для автоматной замены дублирующихся объектов?
Например, у нас из-за переноса из 7.7 предыдущим одмином образовались дублирующиеся ЕдиницыИзмерения (да и не только они). Один элемент пометили на удаление, второй остался. И на него ссылка.
В общем, находим элементы с теми же значениями реквизитов, тока помеченные на удаление, и заменяем ссылки на тот объект, который на удаление не помечен. Ну или как-то так.

[Ушел писать обработку… :-D]
49 Reset
 
17.01.13
14:49
есть обработка ПоискИЗаменаЗначений
50 Reset
 
17.01.13
14:51
(47) не очень хорошо, т.к. при установке пометки могут сработать различные события, подписки, которые могут сделать что-то не то
51 fazendoid
 
17.01.13
14:51
(49) Она ж вручную по одному заменят, если не ошибаюсь?
А у меня их тут много. Сильно много
52 fazendoid
 
17.01.13
15:05
(43) Я кажется понял, что не так. НайтиПоСсылкам() выводит ведь абсолютно любые ссылки на объект? А номенклатуры, на которую ничего не ссылается просто быть не может - как минимум будет заполнено поле единиц измерения, и в ЕдиницыИзмерения.Владелец — ссылка на наш объект. В итоге получаем две идентичные таблицы Справочник.Номенклатура и ВременнаяТаблица.

[Много, много ругательных слов]
Пользователь не знает, чего он хочет, пока не увидит то, что он получил. Эдвард Йодан