Уровни, глубина, прародители, циклы и аналоги запросом

Опубликовал ildarovich в раздел Программирование - Практика программирования

В продолжение публикации «Транзитивное замыкание запросом» [http://infostart.ru/public/158512/] добавлены другие варианты использования того же приема. Приведены запросы для быстрого определения уровней всех элементов справочника, максимальной глубины справочника, прародителей произвольных элементов справочника, запрос для быстрого определения циклов (на примере справочника спецификаций «1С:Управление производственным предприятием») и определения множеств аналогов номенклатуры (также на примере конфигурации «1С:Управление производственным предприятием»).

В предыдущей статье был рассмотрен прием «матричного умножения» в расчете транзитивного замыкания отношений, его теоретическое обоснование и реализация на платформе «1С:Предприятие 8» на примере замыкания иерархии справочника. Из-за того, что данный прием хорошо ложится на возможности конструирования текста запроса на языке 1С, получаемый с использованием этого приема код оказывается очень компактным (всего 9 строк!) и быстрым. Возможно, у кого-то могло сложиться впечатление, что решением одной экзотической задачи с непонятным названием область применения рассмотренного метода и ограничивается. Однако, ЭТО НЕ ТАК! Существуют более приземленные практические задачи, где с большой выгодой можно применить разработанный прием построения запроса. В данной статье рассмотрены сразу пять таких задач.

1. Быстрое определение уровней всех элементов справочника одним пакетным запросом.

При использовании объектной модели для получения уровня элемента иерархического справочника можно использовать функцию «Уровень». Она показывает уровень вложенности текущего элемента справочника, при этом элементы в корне иерархии, вообще не имеющие родителей, имеют уровень «0».

У этой функции два недостатка. Во-первых, она медленно выполняется. Почему это так, понять несложно, если вспомнить, как хранится иерархия в таблицах СУБД. Во-вторых, функция «Уровень» не работает в запросе. А этого как раз очень часто и не хватает: наличие колонки, содержащей уровень иерархии элемента, упростило бы решение многих задач запросами.

Выходом может быть использование следующего запроса и построенной на нем функции

Функция УровниИерархии(ИмяСправочника, МаксимальнаяДлинаПути) Экспорт

   
Пролог = "ВЫБРАТЬ Родитель НачалоДуги, Ссылка КонецДуги ПОМЕСТИТЬ ЗамыканияДлины1 ИЗ Справочник.Номенклатура
            | ГДЕ Родитель <> Значение(Справочник.Номенклатура.ПустаяСсылка)
            | ОБЪЕДИНИТЬ ВЫБРАТЬ Ссылка, Ссылка ИЗ Справочник.Номенклатура;";

   
Рефрен = "ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины#2 ИЗ ЗамыканияДлины#1 КАК ПерваяДуга
            | СОЕДИНЕНИЕ ЗамыканияДлины#1 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
            | УНИЧТОЖИТЬ ЗамыканияДлины#1;";

   
Эпилог = "ВЫБРАТЬ КОЛИЧЕСТВО(НачалоДуги) - 1 Предок, КонецДуги Потомок ИЗ ЗамыканияДлины#2 СГРУППИРОВАТЬ ПО КонецДуги";

   
Запрос = Новый Запрос(СтрЗаменить(Пролог, "Номенклатура", ИмяСправочника));

   
МаксимальнаяДлинаЗамыканий = 1;

    Пока
МаксимальнаяДлинаЗамыканий < МаксимальнаяДлинаПути Цикл

       
Запрос.Текст = Запрос.Текст + СтрЗаменить(СтрЗаменить(Рефрен, "#1", Формат(МаксимальнаяДлинаЗамыканий, "ЧГ=0")), "#2", Формат(2 * МаксимальнаяДлинаЗамыканий, "ЧГ=0"));

       
МаксимальнаяДлинаЗамыканий = 2 * МаксимальнаяДлинаЗамыканий

    КонецЦикла;

   
Запрос.Текст = Запрос.Текст + СтрЗаменить(Эпилог, "#2", Формат(МаксимальнаяДлинаЗамыканий, "ЧГ=0"));

    Возврат
Запрос.Выполнить().Выгрузить()

КонецФункции

Запрос в данной функции отличается от базового запроса из основной статьи только эпилогом. Работа функции построена на следующем наблюдении: так как таблица транзитивного замыкания содержит всех предков любого элемента, то, чтобы определить его уровень, нужно просто посчитать этих предков.

Разумеется, сконструированный внутри функции текст запроса не обязательно сразу выполнять. Его можно сделать частью более общего пакетного запроса, в котором будет использоваться получаемая на последнем этапе таблица. Это касается и всех следующих примеров.

Рассмотрим, для примера, следующую иерархию номенклатуры:

Пример иерархии номенклатуры

Замыкание иерархии вернет следующую таблицу:

Замыкание иерархии

Приведенная функция на основе подсчета предков в замыкании вернет следующую таблицу:

Найденные уровни

2. Быстрое определение максимальной глубины иерархии одним пакетным запросом.

Данная задача может возникнуть, например, при выводе иерархических списков, когда требуется заранее определить  «высоту» (число этажей) отображения списка. Трудность задачи в том, что приходится просматривать все элементы справочника, для каждого из которых необходим вызов  функции «Уровень». Хотя такой код весьма прост,

Функция МаксимальныйУровеньСправочника(ИмяСправочника, Ответ = 0) Экспорт

   
Выборка = Справочники[ИмяСправочника].Выбрать();

    Пока
Выборка.Следующий() Цикл Ответ = Макс(Ответ, Выборка.ПолучитьОбъект().Уровень())
    КонецЦикла;

    Возврат
Ответ

КонецФункции

время его выполнения сильно и неприятно удивляет. В прилагаемой к статье обработке есть кнопка «Ой, глубина», которая вызывает написанную таким образом функцию и позволяет убедиться в большом времени ее работы. Конечно, можно использовать рекурсию, загрузив весь справочник в оперативную память, однако на больших справочниках применение рекурсии также будет не столь эффективным из-за большого количества отдельных вычислений. Пример использования рекурсии приведен здесь [http://nashe1c.ru/materials-view.jsp?id=371]. Решение не  образцовое,  однако доказывает интерес к данной теме.

В результате, наилучшим решением оказывается использование предлагаемого запроса в следующем виде:

Функция ГлубинаИерархии(ИмяСправочника, МаксимальнаяДлинаПути) Экспорт

   
Пролог = "ВЫБРАТЬ Родитель НачалоДуги, Ссылка КонецДуги ПОМЕСТИТЬ ЗамыканияДлины1 ИЗ Справочник.Номенклатура
            | ГДЕ Родитель <> Значение(Справочник.Номенклатура.ПустаяСсылка)
            | ОБЪЕДИНИТЬ ВЫБРАТЬ Ссылка, Ссылка ИЗ Справочник.Номенклатура;";

   
Рефрен = "ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины#2 ИЗ ЗамыканияДлины#1 КАК ПерваяДуга
            | СОЕДИНЕНИЕ ЗамыканияДлины#1 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
            | УНИЧТОЖИТЬ ЗамыканияДлины#1;";

   
Эпилог = "ВЫБРАТЬ ПЕРВЫЕ 1 КОЛИЧЕСТВО(НачалоДуги) - 1 Глубина, КонецДуги Потомок ИЗ ЗамыканияДлины#2 СГРУППИРОВАТЬ ПО КонецДуги УПОРЯДОЧИТЬ ПО КОЛИЧЕСТВО(НачалоДуги) - 1 УБЫВ";

   
Запрос = Новый Запрос(СтрЗаменить(Пролог, "Номенклатура", ИмяСправочника));

   
МаксимальнаяДлинаЗамыканий = 1;

    Пока
МаксимальнаяДлинаЗамыканий < МаксимальнаяДлинаПути Цикл

       
Запрос.Текст = Запрос.Текст + СтрЗаменить(СтрЗаменить(Рефрен, "#1", Формат(МаксимальнаяДлинаЗамыканий, "ЧГ=0")), "#2", Формат(2 * МаксимальнаяДлинаЗамыканий, "ЧГ=0"));

       
МаксимальнаяДлинаЗамыканий = 2 * МаксимальнаяДлинаЗамыканий

    КонецЦикла;

   
Запрос.Текст = Запрос.Текст + СтрЗаменить(Эпилог, "#2", Формат(МаксимальнаяДлинаЗамыканий, "ЧГ=0"));

    Возврат
Запрос.Выполнить().Выгрузить()[0].Глубина

КонецФункции

Для краткости, случай, когда в справочнике нет ни одного элемента, не рассматривается.

Для того же примера глубина будет равна 3

Найденная глубина


3. Определение прародителя (родителя верхнего уровня) в пакетном запросе.

Судя по обсуждениям на форумах, этот вопрос встречается достаточно часто. Широко известно решение, использующее итоги по иерархии [в комментарии (6) к предыдущей статье]. Однако оно не подходит для того, чтобы использоваться в середине пакетного запроса, не дает простой возможности одновременного определения родителей верхнего уровня нескольких элементов и, вероятно, не работает максимально быстро. От этих недостатков свободно следующее решение

Функция Прародители(ИмяСправочника, МаксимальнаяДлинаПути) Экспорт

   
Пролог = "ВЫБРАТЬ Родитель НачалоДуги, Ссылка КонецДуги ПОМЕСТИТЬ ЗамыканияДлины1 ИЗ Справочник.Номенклатура
            | ГДЕ Родитель <> Значение(Справочник.Номенклатура.ПустаяСсылка)
            | ОБЪЕДИНИТЬ ВЫБРАТЬ Ссылка, Ссылка ИЗ Справочник.Номенклатура;";

   
Рефрен = "ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины#2 ИЗ ЗамыканияДлины#1 КАК ПерваяДуга
            | СОЕДИНЕНИЕ ЗамыканияДлины#1 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
            | УНИЧТОЖИТЬ ЗамыканияДлины#1;";

   
Эпилог = "ВЫБРАТЬ НачалоДуги Предок, КонецДуги Потомок ИЗ ЗамыканияДлины#2
            | ГДЕ НачалоДуги <> КонецДуги И НачалоДуги.Родитель = Значение(Справочник.Номенклатура.ПустаяСсылка)";

   
Запрос = Новый Запрос(СтрЗаменить(Пролог, "Номенклатура", ИмяСправочника));

   
МаксимальнаяДлинаЗамыканий = 1;

    Пока
МаксимальнаяДлинаЗамыканий < МаксимальнаяДлинаПути Цикл

       
Запрос.Текст = Запрос.Текст + СтрЗаменить(СтрЗаменить(Рефрен, "#1", Формат(МаксимальнаяДлинаЗамыканий, "ЧГ=0")), "#2", Формат(2 * МаксимальнаяДлинаЗамыканий, "ЧГ=0"));

        МаксимальнаяДлинаЗамыканий = 2 * МаксимальнаяДлинаЗамыканий

    КонецЦикла;

   
Запрос.Текст = Запрос.Текст + СтрЗаменить(Эпилог, "#2", Формат(МаксимальнаяДлинаЗамыканий, "ЧГ=0"));

    Возврат
Запрос.Выполнить().Выгрузить()

КонецФункции

Для того же примера...

Найденные прародители

 

4. Быстрое определение циклов произвольной длины одним пакетным запросом.

Определение циклов основано на следующей идее:

Будем считать уровнем элемента количество прямо или косвенно «предшествующих» ему других элементов (в смысле конкретного отношения). Такой уровень на основе таблицы транзитивного замыкания легко посчитать для ориентированного графа любого вида. Нетрудно догадаться, что уровень всех элементов, находящихся в цикле, будет одинаков. Тогда признаком того, что дуга принадлежит циклу, будет одинаковый уровень ее концов.

В результате получаем следующий запрос, находящий дуги, принадлежащие циклу.

Функция ЦиклыСпецификацийУПП(МаксимальнаяДлинаПути) Экспорт

   
Пролог = "ВЫБРАТЬ Выход.Номенклатура НачалоДуги, Вход.Номенклатура КонецДуги, Выход.Ссылка ПОМЕСТИТЬ ИсходноеОтношение
            | ИЗ Справочник.СпецификацииНоменклатуры.ВыходныеИзделия КАК Выход
            | СОЕДИНЕНИЕ Справочник.СпецификацииНоменклатуры.ИсходныеКомплектующие КАК Вход ПО Выход.Ссылка = Вход.Ссылка
            | ГДЕ Выход.Ссылка.Активная;
            | ВЫБРАТЬ РАЗЛИЧНЫЕ НачалоДуги, КонецДуги ПОМЕСТИТЬ ЗамыканияДлины1 ИЗ ИсходноеОтношение
            | ОБЪЕДИНИТЬ ВЫБРАТЬ НачалоДуги, НачалоДуги ИЗ ИсходноеОтношение
            | ОБЪЕДИНИТЬ ВЫБРАТЬ КонецДуги, КонецДуги ИЗ ИсходноеОтношение;";

   
Рефрен = "ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины#2 ИЗ ЗамыканияДлины#1 КАК ПерваяДуга
            | СОЕДИНЕНИЕ ЗамыканияДлины#1 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
            | УНИЧТОЖИТЬ ЗамыканияДлины#1;";

   
Эпилог = "ВЫБРАТЬ КОЛИЧЕСТВО(НачалоДуги) Уровень, КонецДуги Элемент ПОМЕСТИТЬ ТаблицаУровней ИЗ ЗамыканияДлины#2 СГРУППИРОВАТЬ ПО КонецДуги;
            | ВЫБРАТЬ ИсходноеОтношение.НачалоДуги Предок, ИсходноеОтношение.КонецДуги Потомок, ИсходноеОтношение.Ссылка Спецификация ИЗ ИсходноеОтношение
            | СОЕДИНЕНИЕ ТаблицаУровней КАК Начало ПО ИсходноеОтношение.НачалоДуги = Начало.Элемент
            | СОЕДИНЕНИЕ ТаблицаУровней КАК Конец ПО ИсходноеОтношение.КонецДуги = Конец.Элемент
            | ГДЕ Начало.Уровень = Конец.Уровень";

   
Запрос = Новый Запрос(Пролог);

   
МаксимальнаяДлинаЗамыканий = 1;

    Пока МаксимальнаяДлинаЗамыканий < МаксимальнаяДлинаПути Цикл

       
Запрос.Текст = Запрос.Текст + СтрЗаменить(СтрЗаменить(Рефрен, "#1", Формат(МаксимальнаяДлинаЗамыканий, "ЧГ=0")), "#2", Формат(2 * МаксимальнаяДлинаЗамыканий, "ЧГ=0"));

       
МаксимальнаяДлинаЗамыканий = 2 * МаксимальнаяДлинаЗамыканий

    КонецЦикла;

   
Запрос.Текст = Запрос.Текст + СтрЗаменить(Эпилог, "#2", Формат(МаксимальнаяДлинаЗамыканий, "ЧГ=0"));

    Возврат
Запрос.Выполнить().Выгрузить()

КонецФункции

Запрос приведен на примере проверки зацикливания спецификаций продукции для типовой конфигурации «1С: Управление производственным предприятием». Приведенная функция выдает список связей входов и выходов спецификаций, находящихся в цикле вместе с указанием самих спецификаций. Очевидно, что ошибочной (приводящей к зацикливанию) будет, вероятнее всего, только одна из указанных связей. Можно не ограничиваться только сборочными спецификациями. Но следует учесть, что в этом общем случае могут существовать и правильные циклы сборки-разборки, которые запрос также будет показывать.

Понятно, что такой подход будет обнаруживать циклы любой длины. Безошибочно ограничивать максимальную длину пути можно количеством активных спецификаций, как и сделано в прилагаемой обработке.

Для примера приведен набор спецификаций, содержащий циклы. Это спецификация структуры всем известной детской песни "Вместе весело шагать"

Набор спецификаций с циклами

"Песенка" получается по двум спецификациям: С1(Словечко1 + Словечко2) и С2(Куплет1 + Куплет2 + Куплет3).

Функция, обнаруживающая циклы, вернет следующую таблицу

Таблица дуг циклов

 

5. Определение множества взаимозаменяемых позиций (аналогов) номенклатуры.

Существует несколько решений для хранения информации о взаимозаменяемости номенклатурных позиций [http://infostart.ru/public/128065/]. Например, в УПП для этого используется регистр сведений «АналогиНоменклатуры», в записях которого указывается собственно номенклатура и заменяющий ее аналог (назначение других полей этих записей для данного обсуждения не существенно). Чаще всего можно считать, что если для детали “А” аналогом является деталь “Б”, то верно и обратное: для детали “Б” аналогом будет деталь “А”. Кроме того, если деталь “Б” является аналогом детали “А”, а деталь “В” является аналогом детали “Б”, то деталь “В” также будет аналогом детали “А”.

Как же следует задавать аналоги: по цепочке “А”->”Б”, ”Б”->”В” или звездой “А”->“Б”, ”А”->“В”? - Предлагаемый метод позволяет не задумываться об этом. В любом случае будут найдены все аналоги каждой номенклатуры. Для этого используется функция

Функция ТранзитивноеЗамыканиеАналогии(МаксимальнаяДлинаПути) Экспорт

   
Пролог = "ВЫБРАТЬ Номенклатура КАК НачалоДуги, Аналог КАК КонецДуги ПОМЕСТИТЬ ЗамыканияДлины1 ИЗ РегистрСведений.АналогиНоменклатуры
            | ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ Аналог, Номенклатура ИЗ РегистрСведений.АналогиНоменклатуры
            | ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ Номенклатура, Номенклатура ИЗ РегистрСведений.АналогиНоменклатуры;";

   
Рефрен = "ВЫБРАТЬ РАЗЛИЧНЫЕ ПерваяДуга.НачалоДуги, ВтораяДуга.КонецДуги ПОМЕСТИТЬ ЗамыканияДлины#2 ИЗ ЗамыканияДлины#1 КАК ПерваяДуга
            | ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины#1 КАК ВтораяДуга ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги;
            | УНИЧТОЖИТЬ ЗамыканияДлины#1;";

   
Эпилог = "ВЫБРАТЬ НачалоДуги Предок, КонецДуги Потомок ИЗ ЗамыканияДлины#2 ГДЕ НачалоДуги <> КонецДуги";

   
Запрос = Новый Запрос(Пролог);

   
МаксимальнаяДлинаЗамыканий = 1;

    Пока
МаксимальнаяДлинаЗамыканий < МаксимальнаяДлинаПути Цикл

       
Запрос.Текст = Запрос.Текст + СтрЗаменить(СтрЗаменить(Рефрен, "#1", Формат(МаксимальнаяДлинаЗамыканий, "ЧГ=0")), "#2", Формат(2 * МаксимальнаяДлинаЗамыканий, "ЧГ=0"));

       
МаксимальнаяДлинаЗамыканий = 2 * МаксимальнаяДлинаЗамыканий

    КонецЦикла;

   
Запрос.Текст = Запрос.Текст + СтрЗаменить(Эпилог, "#2", Формат(МаксимальнаяДлинаЗамыканий, "ЧГ=0"));

    Возврат
Запрос.Выполнить().Выгрузить()

КонецФункции

Используя данный запрос, можно существенно сэкономить на хранении информации об аналогах. То есть, вместо указания для каждой номенклатуры всех ее аналогов, можно указать основную позицию и ее заменители «звездой», либо задать аналоги по цепочке, либо пользуясь комбинацией этих подходов – в виде дерева. В результате будет храниться только «остов» отношения аналогии. Например, если в группе взаимозаменяемости 100 деталей, то по максимуму потребуется ввести 100х99 = 9900 записей типа номенклатура-аналог, а в случае хранения только основных записей потребуется хранить всего 99 записей!

На следующем рисунке приведены примеры аналогов. Красным обозначены связи, которые не хранятся в БД.

Пример аналогов

В УПП понадобится 5 записей регистра сведений "Аналоги номенклатуры" для этих связей.

Аналоги в УПП

После транзитивного замыкания аналогии будет сформирована полная таблица аналогов

Полная таблица аналогов

 

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

Еще двум интереснейшим задачам-примерам будет посвящена отдельная статья.

Файлы

Наименование Файл Дата Размер Кол. Скачив.
Отчет "Уровни,Глубина,Прародители"
.erf 10,99Kb
13.11.12
153
.erf 13.11.12 10,99Kb 153 Скачать
Отчет для УПП "Циклы,Аналоги"
.erf 9,29Kb
13.11.12
54
.erf 13.11.12 9,29Kb 54 Скачать

См. также

Лучшие комментарии

70. ildarovich 17.11.2012 21:59
(69)Владимир! – Меньше всего хочу, чтобы Вы огорчались. Знаете, как на флоте борются с тараканами? – Дают им напиться рассола, а потом, когда они захотят пить и вылезут из трюма, задраивают все люки. И НЕВАЖНО – УТОНУТ ОНИ ИЛИ ПОДОРВУТСЯ НА МИНАХ! Так и в моем случае – я придумал прием и написал на его основе несколько запросов для решения известных всем задач. А будут ли исправляться найденные ошибки или списываться найденные аналоги при этом неважно. Вспомните про тараканов – может быть, по ним ударит ракетный крейсер! Статья называется не «разработка высоконагруженной системы для контроля и исправления ошибок зацикливания в ориентированных графах большой размерности». Она называется «Уровни, глубина, прародители, циклы и аналоги ЗАПРОСОМ» и речь идет о ЗАПРОСЕ. Вы сами сузили метод до контроля циклов, присоединили задачу исправления ошибок, надумали ситуацию высокой интенсивности и параллелизма исправления ошибок и огорчились.
Далее, при чем здесь платформа 1С? Прием с тем же успехом можно реализовать в виде RCTE на SQL. Возможно, если бы sql.ru был бы таким же «нарядным» как Инфостарт, я бы предлагал прием там.
Так что не огорчайтесь! Смотрите: весна, все цветет, солнце, птички поют, кенгуру прыгают! – Радуйтесь! Вы скажете – при чем здесь Австралия! Вы притянули за уши надуманную задачу и расстроились. Я присоединил за уши Австралию и обрадовался! Чувствуете разницу? Так что больше позитива – больше креатива! Успехов и вам!
# Ответить
1. AlexProg (файл скачал) 13.11.2012 19:37
ildarovich, спасибо за статью.
Но вот я сижу, и никак не могу представить разузлование спецификации номенклатуры этим методом. Слишком много требуемых параметров при расчете конечного расхода, не буду все перечислять, т.к. это можно увидеть в соответствующей функции в УПП например. Да, если бы нам просто требовались связи, возможно. Но нам требуются не связи, а конечный факт расчета, списания и получения.

По поводу аналогов, они требуются для работы обычного персонала, а не математиков аналитиков. Да и интерфейс последовательной связи аналогов будет весьма замудреным. Покажите мне Вашим способом запрос, который получит конечный расход аналогов по спецификации, с учетом приоритетов, остатков аналогов в НЗП по подразделениям, всех назначенных особенностей использования (с учетом пустых значений, которые "для всех"), расчета с учетом коэффициента и единиц измерения. Не забудьте, что остатки должны списываться последовательно до нуля с учетом приоритетов. У меня например получился один пакетный запрос из 12ти запросов в 800 строк, и это, естественно, с учетом работы типовой функции разузлования спецификаций, и это только для РА, а потом пришлось создавать аналог для ПУ для 4х запросов и связывать вставки кусков с комментариями в первом запросе. Если представить весь алгоритм полностью, натянутым на ваш механизм, то пошло оно все нафиг :) Я и так от этого контура ползаю крабом по столу. Рекурсия куда проще и понятней, я пожалел, что вообще взялся тогда решать эту задачу одним запросом. Не даром этот модуль 1С до сих пор оставляет в полуавтоматическом режиме (распределение аналогов при распределении материалов в спецификации).

Это я тут наумничал к тому, что пока не будет нормальных хранимых процедур делать подобные вещи совершенно дико. Собрать текст запроса по кусочкам в случае работы с иерархией выглядит понятней, проще, а значит удобней для редактирования. Поясню, это лишь моё мнение.
Ответили: (5) (35) (64)
# Ответить
35. hogik 16.11.2012 00:22
(0)
Сергей (ildarovich).
Очень хорошая и интересная статья. Как и все другие Ваши статьи по теме "Делаем запросом". Однако ни одна из них не может иметь практического применения т.к. не учитываются "особенности" многопользовательского и "интерактивного" доступа к информации.
Ну, например, какой смысл в "заранее определить «высоту» (число этажей) отображения списка"(с), если к моменту его реального отображения "высота" может измениться?
Или какой смысл в "определение циклов" на определенный момент состояния БД, если с общей информацией работают (исправляют/плодят циклы) несколько пользователей?
Для решения подобных задач и предложены в 1С способы (инструмент) работы с т.н. "объектной моделью" с привлечением инструментов блокировки отдельных записей/объектов. Увы, медленно работающие т.к. реализуются, опять таки, запросами. И с очень неэффективным выполнением элементарных машинных команд обработки информации в оперативной памяти.
Я понимаю, что в среде 1С-а приходится подбирать алгоритмы под схему базы данных, а не наоборот (как этого требует суть самой идеи БнД) - разрабатывать схему базы данных под постановку изначальной задачи. Но, думаю, даже в этих "узких" рамках можно и нужно разрабатывать алгоритмы имеющие возможность практического применение.
P.S. Поставил "плюс" под публикацию и (1) сообщение.
Ответили: (36) (37) (39)
− 1 [ CratosX; ]
# Ответить

Комментарии

1. AlexProg (файл скачал) 13.11.2012 19:37
ildarovich, спасибо за статью.
Но вот я сижу, и никак не могу представить разузлование спецификации номенклатуры этим методом. Слишком много требуемых параметров при расчете конечного расхода, не буду все перечислять, т.к. это можно увидеть в соответствующей функции в УПП например. Да, если бы нам просто требовались связи, возможно. Но нам требуются не связи, а конечный факт расчета, списания и получения.

По поводу аналогов, они требуются для работы обычного персонала, а не математиков аналитиков. Да и интерфейс последовательной связи аналогов будет весьма замудреным. Покажите мне Вашим способом запрос, который получит конечный расход аналогов по спецификации, с учетом приоритетов, остатков аналогов в НЗП по подразделениям, всех назначенных особенностей использования (с учетом пустых значений, которые "для всех"), расчета с учетом коэффициента и единиц измерения. Не забудьте, что остатки должны списываться последовательно до нуля с учетом приоритетов. У меня например получился один пакетный запрос из 12ти запросов в 800 строк, и это, естественно, с учетом работы типовой функции разузлования спецификаций, и это только для РА, а потом пришлось создавать аналог для ПУ для 4х запросов и связывать вставки кусков с комментариями в первом запросе. Если представить весь алгоритм полностью, натянутым на ваш механизм, то пошло оно все нафиг :) Я и так от этого контура ползаю крабом по столу. Рекурсия куда проще и понятней, я пожалел, что вообще взялся тогда решать эту задачу одним запросом. Не даром этот модуль 1С до сих пор оставляет в полуавтоматическом режиме (распределение аналогов при распределении материалов в спецификации).

Это я тут наумничал к тому, что пока не будет нормальных хранимых процедур делать подобные вещи совершенно дико. Собрать текст запроса по кусочкам в случае работы с иерархией выглядит понятней, проще, а значит удобней для редактирования. Поясню, это лишь моё мнение.
Ответили: (5) (35) (64)
# Ответить
2. iceflash 14.11.2012 06:45
Вот, Вот оно! Автор, молодец=) Интересная статья, интересное решение, полезные идеи/знания. А то уже как то надоели статьи о банальных вещах. Заметно, что задача проработана на "низком" уровне, начиная от реализации хранения данных в СУБД и применения к 1С.

Больше качественного и полезного материала!
+ 1 [ denis_aka_wolf; ]
# Ответить
3. DoctorRoza 14.11.2012 10:07
Хорошая статья, возьму на вооружение
# Ответить
4. alekseies 14.11.2012 10:44
Взял на заметку! буду использоват...
# Ответить
5. ildarovich 14.11.2012 12:38
(1) Разузлование спецификаций номенклатуры этим методом НЕ ПОЛУЧИТСЯ в принципе. Дело в том, что в расчете разузлования потребуется АРИФМЕТИЧЕСКОЕ сложение, а не ЛОГИЧЕСКОЕ, а значит, в формуле появятся биноминальные коэффициенты, которые будут "портить" расчет количества. Один и тот же путь вхождения будет учтен несколько раз в зависимости от его длины. Тут уже был был спор с моим участием, что лучше - запрос или рекурсия в расчете разузлования. Был ранее и остаюсь сейчас сторонником текущего решения в УПП, то есть рекурсии. Тут я на той же стороне, что и Вы и нам спорить не о чем. Почему Вы решили, что речь идет о разузловании? Возможно, Вас смутили слова "определять входимость деталей в узлы и готовые изделия по их спецификациям". Здесь я понимал под входимостью (смотрел в словаре) факт вхождения (да или нет), а не количество деталей в узле. Наверное, нужно было выразиться определеннее.
По-поводу аналогов. Пользователя не нужно пугать терминами. Ему нужно дать возможность вводить информацию в любом удобном и компактном виде, а перед использованием (или проверкой) разворачивать все аналоги, в том числе выводимые из основных. Второе, более тонкое, соображение, касается автосписания по спецификациям с учетом аналогов, приоритета, наличия и прочее. Неоднократно приходилось спорить с пользователями, которые ОШИБОЧНО считают автосписание частью автоматизации, потому что сам СЧИТАЮ АВТОСПИСАНИЕ ЗЛОМ. Вместо учета нас заставляют моделировать действительность. Обратная связь - основа управления - разрывается! Мы перестаем знать, что НА САМОМ ДЕЛЕ пошло на выпуск. Однако эти рассуждения уже не по теме данной статьи.
+ 1 [ CratosX; ]
# Ответить
6. AlexProg (файл скачал) 14.11.2012 12:59
ildarovich, ну если Вы согласны со мной, что в реальности выбранные примеры прикладного использования Вашей методологии не корректны, тогда согласитесь: примеры выбраны не удачно, или методика использоваться будет крайне редко.

По поводу автосписания, действительно долгий и не нужный спор. Я автоматизирую крупные предприятия, где "расставлять флажки" списания аналогов не реально в принципе. Тысячи наименований аналогов и их текущие разбитые остатки в НЗП. Поэтому делается одним этапом в конце периода подводя под инвентаризацию. Здесь без автосписания аналогов по исходным комплектующим из спецификаций никак в принципе. Ваши же размышления более походят на теоретические, хотя, безусловно, доля смысла в них есть.
Ответили: (7)
# Ответить
7. ildarovich 14.11.2012 13:26
(6) Совсем не хочу соглашаться с тем, что
в реальности выбранные примеры прикладного использования Вашей методологии не корректны ... примеры выбраны не удачно, или методика использоваться будет крайне редко
Во-первых, предлагается не методология и не методика, а прием. Примеров (пока) шесть:
1) определение всех предков всех потомков всех элементов(транзитивное замыкание) - написать первоначальный запрос и статью меня побудили два вопроса в форуме - значит, этот вопрос интересен, а решения никто кроме меня не предложил;
2) определение уровней всех элементов справочника - есть статья, где тот же вопрос решается гораздо более громоздким способом;
3) максимальная глубина справочника - долгий цикл или громоздкий метод на Наше1С (автор, видимо, задачу не из пальца высосал);
4) прародители - на мисте штук шесть веток про решение через ИТОГИ В ИЕРАРХИИ - там, что, одни теоретики собрались?
5) циклы в спецификациях - две статьи на Инфостарте. В одной - запрос в цикле, в другой процедура до 10 уровней максимум. Откуда взята проблема? Не из практики?
6) аналоги - посмотрите внимательно рисунок в статье: 5 записей в регистре и 14 в результате. Это реальная задача.
Ответили: (10)
+ 1 [ Amara; ]
# Ответить
8. AlexProg (файл скачал) 14.11.2012 14:19
ildarovich, не люблю я спорить. Но уж ладно, поспорю:
1,2,3,4,5 Изначально требовалось написать один пакетный запрос, без дополнительных построений. Так что Вы задачу не решили. Конструировать запрос средствами языка можно для любой из этих задач, причем более эффективно, чем у Вас. Для каждой конкретной задачи имеется ввиду.
6. Изначально задача туповатая. Имея лишь справочник номенклатура, невозможно пользоваться всеми преимуществами аналогового учета, как например в УПП. Просто человек не в теме.

Некоторые на нашей памяти прикручивали ООП к 1С помница. Да, достоинств много, но нафиг никому не нужно.
Решение у Вас красивое, умно выглядит. Но на практике для меня например совершенно не применимо.
Больше не буду спорить, сорри :)
Ответили: (9)
# Ответить
14. bulpi 14.11.2012 15:42
автору большое спасибо за
1)Решение важных народохозяйственных задач :)
2)интеллектуальное удовольствие.

Извини, но не понял пункт 4 с песенкой. Можно ткнуть пальцем, где там цикл ? я цикла не вижу. Куплет не состоит из песенок.
Ответили: (32)
# Ответить
24. kapustinag 15.11.2012 00:01
А по теме публикации - считаю, очень полезно. Именно потому, что древовидные запросы (задача, которая в СУБД Oracle решается штатно, т.к. в синтаксисе SQL-запросов предусмотрена специальная фраза для этого) - в 1С каждый строит сам, изобретая велосипед. Поставил бы еще плюсик-другой, если бы можно было.
# Ответить
30. iceflash 15.11.2012 10:46
Браво!=)
# Ответить
32. ildarovich 15.11.2012 13:22
(14) В каждом из трех куплетов есть слова "раз словечко, два словечко - будет песенка". Если в этом месте вместо произнесения слова "песенка" начинать то, что она обозначает, то есть саму песенку, то дети "зациклятся".
# Ответить
35. hogik 16.11.2012 00:22
(0)
Сергей (ildarovich).
Очень хорошая и интересная статья. Как и все другие Ваши статьи по теме "Делаем запросом". Однако ни одна из них не может иметь практического применения т.к. не учитываются "особенности" многопользовательского и "интерактивного" доступа к информации.
Ну, например, какой смысл в "заранее определить «высоту» (число этажей) отображения списка"(с), если к моменту его реального отображения "высота" может измениться?
Или какой смысл в "определение циклов" на определенный момент состояния БД, если с общей информацией работают (исправляют/плодят циклы) несколько пользователей?
Для решения подобных задач и предложены в 1С способы (инструмент) работы с т.н. "объектной моделью" с привлечением инструментов блокировки отдельных записей/объектов. Увы, медленно работающие т.к. реализуются, опять таки, запросами. И с очень неэффективным выполнением элементарных машинных команд обработки информации в оперативной памяти.
Я понимаю, что в среде 1С-а приходится подбирать алгоритмы под схему базы данных, а не наоборот (как этого требует суть самой идеи БнД) - разрабатывать схему базы данных под постановку изначальной задачи. Но, думаю, даже в этих "узких" рамках можно и нужно разрабатывать алгоритмы имеющие возможность практического применение.
P.S. Поставил "плюс" под публикацию и (1) сообщение.
Ответили: (36) (37) (39)
− 1 [ CratosX; ]
# Ответить
36. ildarovich 16.11.2012 18:24
(35) Владимир! Рад, что обратили внимание на статью, тем более именно Вы и были одним из первых, кто увидел (и оценил) этот прием в обсуждении двухлетней давности "Реально написать хитрый запрос". Интересный вопрос я придумал не сам себе, а увидел его в форуме. Автор вопроса - Шепталов Станислав. Далее - 24.10.12 тот же (только что обратил на это внимание, так как никнэйм разный) участник форума задал похожий вопрос, но уже в применении к иерархии. Получается, что решен ПРАКТИЧЕСКИЙ вопрос. Далее, в соответствии с "научным" подходом я просмотрел практические задачи, где может применяться этот прием. Нашел еще 7 задач. 5 - в этой статье. Среди них задачу про циклы в спецификациях, которую я ранее обещал решить Ish_2 одним запросом. Думаю, Ish_2 сможет убедить Вас в актуальности этой задачи - он потратил на нее немало времени. Решение короткое - из нескольких строк, поэтому предельно понятное, сформулированное в непроцедурном стиле, через требование к результату. Ну и другие задачи встречались в статьях и на форуме, для них предлагались более громоздкие решения. Поэтому давайте подождем некоторое время, чтобы понять, как часто это будет применяться. Именно такой обратной связи я жду - от тех, кто будет пробовать.
Кстати, о том, что эта ветвь математики недалека от практики и нужна бухгалтерам свидетельствует общий модуль "КорректировкаСтоимости" в БП2, с которым как раз сейчас возимся (нестабильная работа штатного запроса). Там идет речь о разрыве циклов графа перемещений номенклатуры и построении остовного дерева.
Теперь о структуре базы данных «под конкретную задачу». Вопрос был задан про реализацию задачи на 1С и, поэтому, задача была решена на 1С. Если бы Вас спросили «на каком автобусе можно доехать до библиотеки», а Вы бы ответили, что лучше лететь на дирижабле, то Вас бы просто не поняли (может быть, кроме тех, кто стоит в московской пробке). Первоначально метод работал на совсем другом языке.
Вообще я не смогу Вас переубедить, когда Вы считаете, что архитектура платформы 1С никуда не годится. Могу лишь высказать свое мнение. Разрабатывать схему БД с нуля под конкретную задачу дорого. Если сравнить со строительством: 1С – это панельные многоэтажки – дешевое жилье – средство массовой автоматизации – в тесноте, да не в обиде. Единичные организации могут нанять Нормана Фостера для точной реализации своих требований. Остальным приходится использовать дешевые массовые проекты – реляционные СУБД с жесткой объектной моделью. Кроме того, знаком с печальным опытом использования Caсhe в нескольких проектах. Глазами разработчика все выглядит совсем не так радужно, как в теории. Объектная модель 1С выдерживает проверку временем – «застроены и заселены огромные территории». Кроме того, она развивается. Недавно появилась технология внешних источников данных. И если в какой-то задаче требуется более высокая реактивность (например, биллинговые системы), теперь можно бесшовно состыковать 1С с другой СУБД. У нас, например, так сделан обмен с импортной ERP.
Но все же не хотел бы уводить разговор от основной темы – работы предлагаемых приемов в детально описанных ПРАКТИЧЕСКИХ задачах.
Ответили: (39)
+ 1 [ hogik; ]
# Ответить
37. ildarovich 16.11.2012 18:55
(35) И еще относительно параллелизма и блокировок. «Рассуждая на пальцах», можно представить себе любое сочетание событий. Более точным будет произвести количественную оценку. Это можно сделать с использованием моделей систем массового обслуживания (СМО). Если рабочий процесс 1 (кластера нет), то модель будет относиться к классу N/M/1. Здесь N – число пользователей, M – максимальная длина очереди (могу напутать что-то в обозначениях, заранее извиняюсь). Зная время выполнения запроса и число пользователей, максимальное время ожидания блокировки, Вы по любому учебнику по СМО определите «вероятность отказа в обслуживании». Подставив в него РЕАЛЬНОЕ время выполнения «моего» запроса, РЕАЛЬНУЮ интенсивность внесения изменений в соответствующий справочник (ну не автоматами же они генерируются), РЕАЛЬНОЕ количество одновременно работающих пользователей, Вы получите число со многими нулями – очень малую вероятность. Это ведь НСИ, она по определению меняется нечасто. Выпуск каждого нового вида продукции или изменения технологии – это целое дело (плавали, знаем). Возьмите из журнала регистрации РЕАЛЬНЫЕ данные по интенсивности работы со справочником спецификаций, контрагентов, номенклатуры для обычного предприятия! Поэтому меня больше беспокоит непонятность приема, его ненужность, большое время выполнения запроса в задачах с «неудобными» данными, а это выявит практика.
Ответили: (38) (61)
# Ответить
38. AlexProg (файл скачал) 16.11.2012 19:30
(37) ildarovich, Вы можете написать конкретную задачу просто и ясно без философии, где бы применялся этот метод. Только не теоретическую из головы, а конкретную задачу учета? Просто: дано это это, получить то-то то-то, где ваш метод будет действительно эффективен. Может тогда я вам поверю.
Ответили: (40)
# Ответить
39. hogik 16.11.2012 19:42
(36)
"Получается, что решен ПРАКТИЧЕСКИЙ вопрос."(с)
Сергей (ildarovich).
Нет. Предложен способ выхода из угла, в который сами себя загнали. :-(
В рамках 1С-возможностей совершенно реально и логичнее обеспечить, например, проверку "циклов" в процессе ввода информации. Равно как и обеспечить «высоту» для последующего её получения ОДНИМ обращение к БД. И для решения этих задач совершенно не требуется каждый раз перебирать "всю" информацию.
Я совершенно "не против" красивых/эффективных алгоритмов обработки информации запросами. Но всему свое место. Запрос для пакетной обработки информации (отчетов). Прямой доступ для "интерактивных" многопользовательских систем. Разные задачи (цели). Разные способы (алгоритмы) решения. Разные инструменты. Разные схемы БД (даже в рамках реляционной модели!!!).
Т.е. я об этом написал в (35) сообщении...
P.S. Соглашусь с Вашим отнесением подобных решений к практическим, если Вы дадите описание алгоритма поиска "циклов" и ИСПРАВЛЕНИЯ "циклов" запросами в многопользовательской среде. И так, чтобы эта задача не превращалась в подобие перфокарточной/пакетной технологии середины прошлого века.
# Ответить
40. ildarovich 16.11.2012 21:47
(38) Могу привести, например, такой случай из практики: В начале июля этого года у нашего клиента - крупной торговой компании перестал проходить обмен УТ->БП (свои правила обмена через прямое подключение). Очень большие базы, сильно переписанная УТ10.3, автоматизированы все обмены: с импортной WMS, производством, таможней, поставщиками, филиалами и контрагентами, работа 24х7. Естественно, кластер серверов, MSSQL2008, система хранения. Разбирались 1,5 дня, задержали отчет иностранному владельцу, был скандал. Выяснилось: зацикливание справочника номенклатура! (Можете почитать: "Что бывает, когда родитель ушел в себя") Саму первопричину не нашли, ситуация никак не воспроизвелась - сейчас платформа не позволяет этого делать в принципе. Понятно, что виновато какие-то сочетание событий в обменах и в СУБД. Тем не менее для подстраховки теперь можем применять контроль зацикливания. Может быть, это не совсем такой пример, которого Вы просили, но
Когда б вы знали, из какого сора
Растут стихи, не ведая стыда
Ответили: (41) (42) (54)
# Ответить
41. AlexProg (файл скачал) 16.11.2012 22:17
(40) ildarovich, не понял, вы использовали этот механизм при обмене? Или просто для контроля зацикливания?
Ответили: (43)
# Ответить
42. AlexO (файл скачал) 16.11.2012 22:23
(40) ildarovich,
перестал проходить обмен УТ->БП

Выяснилось: зацикливание справочника номенклатура!

и причем тут ваш метод, где допущена обычная для 1с-ника ошибка?
Почему обычная? Потому что 1С "настраивает" всех своих программистов не на ПРЕДУПРЕЖДЕНИЕ и ПОИСК ошибок на этапе разработки, а исправление по факту по принципу: "Если ничего не случилось - ну и ладно".
А по-простому - "авось, пронесет".
Саму первопричину не нашли

да, в 1С сделано все, чтобы было как можно запутаннее, не говоря уже об отсутствии инструментов моделирования работы обработок\обменов, контроля исполнения кода и редактирования понаделанного и понаписанного.
Ответили: (44)
# Ответить
43. ildarovich 16.11.2012 22:26
(41) Да, в этом случае, просто для контроля зацикливания
# Ответить
44. ildarovich 16.11.2012 23:01
(42) Уважаемый AlexO! В мире нет ничего идеального. В том числе нет идеальных программ. Например, в программном обеспечении лунной миссии Appolon после первого запуска было найдено более 100 ошибок. 1С не хуже и не лучше других платформ. Это нормальный эволюционирующий в нужную сторону инструмент для своего класса задач. Прошу понять: для меня разговор 1С - плохая - бессмысленный разговор, он ни к чему не ведет, ни к чему не побуждает. К тому же мне неудобно за Вас: получается, что за глаза Вы обижаете людей (разработчиков платформы), которых я безусловно уважаю. В программном коде платформы 8.3 около 10 миллионов строк на С++. И это (здесь я имею ввиду все версии платформы) нормально работает! Более чем у миллиона пользователей! На нескольких программных платформах, в том числе мобильных iOs, Android, с несколькими СУБД, с отказоустойчивостью и в облаках тоже.
А мой метод (прием) при том, что он позволяет , например, в этом конкретном случае обнаружить ошибки, появившиеся в результате программного сбоя (у этого термина есть точное определение), сэкономить время и нервы большого количества людей.
Ответили: (45)
# Ответить
45. AlexO (файл скачал) 16.11.2012 23:43
(44) ildarovich,
А мой метод (прием) при том, что он позволяет ...обнаружить ошибки,

так есть несколько способов сделать это, окромя вашего метода.
миссии Appolon после первого запуска было найдено более 100 ошибок.

и их не исправили, как это делают в 1С?
В программном коде платформы 8.3 около 10 миллионов строк на С++. И это нормально работает!
оно может на выставочных стендах и нормально работает (хотя вот у Microsoft виснет и на стендах).
А вот в реальных базах в конце концов все тухнет и падает, хоть в 8.1, хоть в 8.2, и 8.3 - что, выделяется из этого ряда?
которых я безусловно уважаю

я вот ... не могу уж очень сильно уважать РАЗРАБОТЧИКОВ ЯП, в котором сделано многое для запутывания разработки и усложнения интерфейса между этим самым ЯП и разработками, которые он пытается усиленно пользовать.
Ответили: (46)
# Ответить
46. ildarovich 16.11.2012 23:53
(45)
так есть несколько способов сделать это, окромя вашего метода.
- опишите, пожалуйста, эти способы. Я постараюсь показать выгодные отличия.
А вот в реальных базах в конце концов все тухнет и падает, хоть в 8.1, хоть в 8.2, и 8.3 - что, выделяется из этого ряда?
- приведите, пожалуйста, конкретные примеры. Желательны не общие слова, а подробные технические детали.
Ответили: (47)
# Ответить
47. AlexO (файл скачал) 16.11.2012 23:55
(46) ildarovich,
так мы еще и в старой теме обсуждали варианты поиска родителей...
чем ваш-то метод отличается? В какую сторону? Результат-то то же :)
Ответили: (48)
# Ответить
48. ildarovich 16.11.2012 23:58
(47) Поиск родителей и контроль зацикливания - это СОВЕРШЕННО разные задачи. С еще большим интересом жду ответа на вопрос
так есть несколько способов сделать это, окромя вашего метода.
Ответили: (49)
# Ответить
49. AlexO (файл скачал) 17.11.2012 00:07
(48) ildarovich,
т.е. ваш поиск Родителей - это уже контроль зацикливания, правильно?
Ну открывайте тему тогда новую :)
В последних двух Ваших темах не просматривается какой-либо механизм контроля зацикливания чего-либо.
Разверните мысль тогда.
Потому как представленный в этой статье пример "контроля зацикливания" реализован все на той же проверке иерархии родителей и сравнении между родителей элементов между собой (выявляются цепочки Родитель1 - Потомок1, он же Родитель 2 - Потомок2, который Родитель3 - Потомок3 (который одновременно является Родитель1) - видите, вся суть статьи в одном предложении :)), коя реализутся - правильно, - не только вашим методом :)
Если вы реализовали некий механизм контроля, используя свой метод поиска родителей - так и описывайте именно его, а не рассказывайте о своей статье "О родителях" как о статье "Контроль зацикливания".
Сначала хотя б напишите её, чтоб было, что обсуждать :)
Ответили: (50) (51)
− 1 [ CratosX; ]
# Ответить
50. ildarovich 17.11.2012 00:31
(49) Смотрите, предлагается ПРИЕМ: В запросе некоторая исходная таблица соединяется сама с собой. Потом результат снова соединяется сам с собой, потом этот результат снова соединяется сам с собой и так далее. Если в исходной таблице были пути длины один, то после 10-го соединения так получатся пути длины тысяча (два в десятой степени). Если в исходной таблице в одной строке были непосредственно знакомые с друг другом люди, то во второй таблице - знакомые знакомого, в третьей - знакомые - знакомого знакомого знакомого (именно четыре!). А в десятой Вы будете рядом, даже если Вы были знакомы через тысячу посредников. Эта последняя таблица называется таблицей транзитивного замыкания.
Ее БЫСТРЫЙ способ получения позволяет решить несколько совершенно РАЗЛИЧНЫХ практических задач (об этом вторая статья).
Например, определить всех опосредствованных родителей любого элемента справочника. А раз всех, значит, первоначальных, я их назвал прародителями (родоначальники). Это можно сделать и другим способом, как Вы правильно заметили, но НЕ В ПАКЕТНОМ ЗАПРОСЕ и НЕ ТАК БЫСТРО как "моим" способом.
На базе той же таблицы можно НАЙТИ ЦИКЛЫ - это совершенно другая задача. Из другой оперы, так сказать. Для этого сначала считается уровень каждого элемента. Под уровнем понимается число записей, в которых элемент справа. Далее находятся записи в исходной таблице, уровень элементов в которых одинаков. Не очевидно, но такие записи образуют цикл! А обработка их супербыстро находит!
Поэтому очень Вас еще раз прошу ответить, какие способы Вы имели в виду, говоря
так есть несколько способов сделать это, окромя вашего метода.
# Ответить
51. ildarovich 17.11.2012 00:43
(49) Статья называется
Уровни, глубина, прародители, циклы и аналоги запросом
Про это там и написано. Про поиск циклов - в пункте 4. Вместе СО ВСЕМ ИСХОДНЫМ КОДОМ. Больше никакого кода не требуется! Код нарочно развернут, снабжен отступами и самодокументирующими названиями переменных. Он должен быть понятен. Приведен рисунок и скриншот обработки после вызова метода для спецификаций рисунка. В комментариях к первой статье я привел получающийся текст развернутого запроса. Привел работающую обработку для того, чтобы можно было проверить метод на своих данных. Что еще я мог бы написать про этот метод, чтобы быть понятым?
Ответили: (52)
+ 1 [ CratosX; ]
# Ответить
52. AlexO (файл скачал) 17.11.2012 00:54
(51) ildarovich,
Про поиск циклов - в пункте 4. Вместе СО ВСЕМ ИСХОДНЫМ КОДОМ

тогда чем код в п.4 отличается от кода поиска родителей из "Транзитивного запроса"?
Ответили: (53)
# Ответить
53. ildarovich 17.11.2012 01:12
(52) Он отличается "прологом" и "эпилогом". Пролог отличается тем, что формируется еще одна временная таблица, запоминающая исходное отношение. Кроме того, само отношение строится из входов и выходов активных спецификаций. Эпилог отличается тем, что рассчитываются уровни, а затем исходная таблица соединяется с двумя таблицами уровней для левого и правого элемента и "режется" по условию равенства уровней. Все снабжено описанием и это прямо и ясно написано в коде.
Ответили: (55)
# Ответить
54. AlexProg (файл скачал) 17.11.2012 01:12
(40) ildarovich, пример конечно явно надуманный. В любом случае, имея сбой на уровне платформы вы обязаны избавиться от него в первую очередь, а не встраивать сервисные механизмы в горлышко. (Не знаю, что у вас там за канал). AlexO, уже написал всё. Избавится можно как на уровне платформы, так и на программном уровне, 1С отрабатывает зацикливание иерархии. Оставляя ошибку вы наживаете себе серьезный геморрой, т.е. лечите симптом.

Я понимаю, вы бы еще привели пример с зацикливанием реквизитов, более реалистичный. Но опять же, легко решается кстати без выстраивания всей цепочки.

Ваши разработки могут служить лишь для собирания статистики в запущенных случаях. Кому она нужна, вопрос.

P.S. Я вспомнил один подобный случай, еще на 8.0 давно очень. Обмен явно издевался и выстраивал перепендикулярный гемор, как раз по связи владелец-реквизит. В конфигурации был очень хитроперевернуто решен механизм комплектации, который по сути повторял 7.7. того-же творца. Так вот, паренек, который на тот момент работал с 1С меньше года решил эту проблему на SQL, и за что был анально покаран. После этого, он написал триггер, который пузырьковал эту штуку. Я его реально зауважал. Вот, стремитесь. Это всё не сложно, логично и выглядит действительно круто.
Ответили: (56) (57) (59)
# Ответить
55. AlexO (файл скачал) 17.11.2012 01:29
(53) ildarovich,
Он отличается "прологом" и "эпилогом".

т.е. поиск
ГДЕ Родитель1 = Потомок3 
из примера ( 49) решается исключительно данным способом?
Или - зачем такие сложности, Сергей, для решения вышеуказанной задачи? :)
Ответили: (58)
# Ответить
56. ildarovich 17.11.2012 01:30
(54) Слово "надуманный" здесь никак не подходит. Это АБСОЛЮТНО РЕАЛЬНЫЙ случай. Чтобы локализовать эту проблему, требуются диагностические инструменты. Этот запрос - он и есть(еще раз повторю, это один из примеров его применения). Мы не можем позволить себе контролировать каждую запись в справочник на зацикливание, перепроверяя платформу. Это скажется на быстродействии. Поэтому контроль именно в том месте, где нужно - перед проблемной операцией. С тех пор еще много чего в профилактических целях делали, сбой не повторялся.
Пример с зацикливанием реквизитов я привел в основной статье в пункте 4. Спасибо, что сочли его реалистичным.
# Ответить
57. AlexO (файл скачал) 17.11.2012 01:32
(54) AlexProg,
который пузырьковал эту штуку

так обкатанные методы обработки данных не отменены нигде, кроме 1С :)
# Ответить
58. ildarovich 17.11.2012 01:35
(55) Сложность в том, что число уровней в "моем" методе ничем не ограничено. Он решает и задачу тогда когда Вам потребуется сделать ТЫСЯЧУ СОЕДИНЕНИЙ, проверяя
Где Родитель1 = Потомок1000
, а мне всего 10. В общем, попробуйте.
# Ответить
59. ildarovich 17.11.2012 01:43
(54) Если Вы все же захотите действительно разобраться в сути этого приема, то Вы поймете, что он также будет многократно ускорять и решение подобных задач на чистом SQL.
пример с зацикливанием реквизитов ... легко решается кстати без выстраивания всей цепочки.
- попробуйте ка доказать это утверждение! - Очень хочется посмотреть!
По прежнему жду от AlexO подтверждения того, что
так есть несколько способов сделать это, окромя вашего метода.
Ответили: (60)
# Ответить
60. AlexProg (файл скачал) 17.11.2012 02:05
(59) ildarovich, Решение реквизитов лично я делал кучей способов.
Например движение из двух точек к центру быстрей, чем движение от А до Б метода цепочки.

И кстати, всегда метод пересечения подмножеств, будет быстрей цепочки, если нужно собрать всю статистику разом, даже при количестве записей более миллиона.

И еще я бы рассмотрел анализ прямой вложенности запроса, при условии, что она работает на 10% быстрее, в случае длинных связей большой прирост производительности. Другой вопрос, где оно обломается, я думаю вы уже обсуждали этот вопрос.

Но это философия. Если правильно архитектурно подходить, то необходимо создавать систему контроля при вводе данных и где не критична скорость, потому что проконтролировать использование таких данных, вы можете только тогда, когда сами продолжаете разработку. А это в наше время непозволительная роскошь. А вас потом вспомнят "добрым словом".
Ответили: (62)
# Ответить
61. hogik 17.11.2012 03:56
(37)
Сергей (ildarovich).
Очень огорчил меня этот Ваш текст.
Попробую привести пример:
Имеем в базе данных иерархическую структура. Не имеет значение её прикладное назначение и "интенсивность внесения изменений"(с). По определению "задачи" в ней могут быть "циклы". Их надо искать и исправлять. Запускаем Ваш алгоритм. Получаем информацию о нескольких "циклах". Хотим исправить ошибки побыстрей. Сажаем двух операторов. И они начинают исправлять ошибки. Допустим, что самым простейшим способом - удалением "плохих" узлов. Смотрят, грубо говоря, каждый в свою "распечатку". Какова вероятность того, что один из операторов начнет исправлять уже исправленный "цикл" другим оператором? Т.е. им надо обеспечить постоянное обновление "распечатки" с учетом изменений после каждой процедуры исправления? Каким алгоритмом это следует делать? Как учесть в Вашем алгоритме тот факт, что в момент его выполнения под нужды одного оператора, другой оператор уже "прицелился" к очередному "циклу" и "нажимает" кнопку удаления?
Ответили: (63)
# Ответить
62. ildarovich 17.11.2012 09:08
(60)
Решение реквизитов лично я делал кучей способов
Убедительно Вас прошу, приведите все, какие вспомните из этой "кучи"! Пока это только слова. Тогда я Вам смогу нагляднее показать, в чем практическая выгода "моего" способа.
# Ответить
63. ildarovich 17.11.2012 09:27
(61) "Замечено, что ОДНОВРЕМЕННОЕ нажатие четырех кнопок на клавиатуре дает более интересные эффекты, чем одновременное нажатие трех" (шутка)
Хотим исправить ошибки побыстрей. Сажаем двух операторов.
- просто не делайте этого! (организационное решение) "Поспешишь - людей насмешишь" (народная мудрость). Если Вам нужно организовать работу в коллективе - первым делом нужно "распределить работу". А давать задачу "на собачку-драчку" - кто быстрее найдет ошибку - это для игры, а не для серьезных дел, тем более, исправления ошибок! Кроме того, есть механизм управляемых блокировок. (программно-техническое решение). Если же у Вас специализированная система по "разрыву циклов" с большим потоком входящих требований (пока не вижу реальной задачи для такой системы) следует добавить дополнительные таблицы (справочники, регистры сведений), разбить граф на кластеры, назначить ответственных, придумать систему диспетчиризации.
Ответили: (69)
# Ответить
64. ildarovich 17.11.2012 09:34
(1) Не хотел отвлекаться от темы, но все же было бы интересно взглянуть на Ваш запрос из 800 строк. Вы можете оформить его как обработку заполнения табличной части "Распределения материалов на выпуск". Штатный механизм не учитывает аналогов, так что будет интересно. Дело в том, что я тоже решал эту задачу. В моем запросе строк было ГОРАЗДО меньше. Правда, с темой данной статьи это не связано.
Ответили: (65)
# Ответить
65. AlexProg (файл скачал) 17.11.2012 11:49
(64) ildarovich, я конечно понимаю, что вам интересно. Но та разработка работает на паре крупных заводов и дает очень быстрый результат. И соответственно стоит не мало денег. И её нигде больше нет :) Придумывайте сами.

Кстати, я знаю (сейчас вот подумал), как решить задачу зацикливания значений реквизитов или зацикливания значений реквизитов табличной части одним пакетным запросом, причем всего с одной или двумя временными таблицами (в зависимости от способа). Т.е. будет работать на много быстрей вашего способа или способа вложенности, так как крутит всего одну индексированную или две таблицы, а не кучу обращений к базе данных. Более того, это способ, результат которого можно снабдить связанными данными, т.е. он будет иметь практическое применение. Его можно разворачивать последовательно или параллельно, т.е. в одну или в две стороны. Можно получать замкнутые или разомкнутые системы и весь путь от начала до конца, а не только начало и конец.
Да запрос будет выглядеть дико, иметь только конечное число разворачиваний. При динамическом задании количества разворачиваний можно сделать динамическое построение запроса. Вот про это может напишу статью, хотя опять же нормальный человек просто будет использовать рекурсию при контроле например при записи или в сервисном механизме, подумаю надо ли мне позорится.
Ответили: (66)
− 1 [ CratosX; ]
# Ответить
66. ildarovich 17.11.2012 12:14
(65) Опять одни слова - ни строчки кода. Значит, той разработки тоже нет. Предлагаю отложить все разговоры до того, когда Вам будет что предъявлять в доказательство своих пока безосновательных умозаключений. Пока из последовательности Ваших мыслей-слов сделал вывод, что в сути моего метода Вы не разобрались, а жаль.
Ответили: (67)
# Ответить
67. AlexProg (файл скачал) 17.11.2012 12:26
(66) ildarovich, да да, куплюсь я на дешевый вызов. Мне тут соревноваться не с кем и не зачем. Для возможности неограниченно скачивать разработки мне хватило древнего архива иконок :) И не хочу прослыть рождателем г...окода. Это вам заняться не чем.

Если действительно интрересно, то на мое решение зацикливания меня навел способ, который используется в C# при обработке LINQ запроса обобщенных типов. И при получении его результата в виде дерева. Ну или как обрабатывается динамические параметры обобщенных типов при формировании кортежа в том же C#. Учите мат часть, а не скрипите зубами (как уже тут кто-то писал).
Ответили: (68)
# Ответить
68. ildarovich 17.11.2012 14:50
(67)
да да, куплюсь я на дешевый вызов
- это означает, что Вы представите все таки когда-нибудь наконец какие-либо доказательства?
Мне тут соревноваться не с кем и не зачем
- зря Вы так, соревноваться вообще полезно. Впрочем, я тоже иногда повторяю за рулем:
Да кто такой этот Шумахер? - Он меня ни разу не обгонял!
Пока Ваше решение - это еще совсем не решение. Его никто не видит. Но действительно интересно будет посмотреть. Матчасть учу постоянно, скрипеть зубами привычки нет.
# Ответить
69. hogik 17.11.2012 19:04
(63)
"просто не делайте этого! (организационное решение)"(с)
Сергей (ildarovich).
Эта шутка мне больше понравилась, чем про три клавиши. :-)
Еще раз на пальцах.
Запрос - это пакетная обработка информации.
Пакетная обработка имеет ряд "характеристик" (упрощенно говоря!!!):
1) Скорость выполнения.
2) Количество информации "вовлеченной" в получение результата.
3) Время актуальности конечного результата.
Вы сосредоточились ТОЛЬКО на первом пункте.
Но по сути ВСЕХ Ваших решений требуется выполнять "интерактивную" обработку информации на основании результатов "пакетной" обработки. Чем больше информации "вовлечено" в получение результата пакетом, тем выше вероятность потери её актуальности. И меньше времени она является актуальной.
Для решения этой "проблемы" применяются блокировки. В Ваших алгоритмах требуется блокировка ВСЕЙ таблицы на ВСЁ время выполнения "пакета" и последующего воздействия на информацию в интерактивном режиме. Т.е. - однопользовательский режим обработки информации. И уменьшение времени выполнения "пакета" - это только "Игры разума"(с).
Сергей. Это элементарные, очевидные вещи. Если не смотреть на задачи "узко-конкретно"(с).
Я очень огорчен. Желаю успехов...
Ответили: (70)
# Ответить
70. ildarovich 17.11.2012 21:59
(69)Владимир! – Меньше всего хочу, чтобы Вы огорчались. Знаете, как на флоте борются с тараканами? – Дают им напиться рассола, а потом, когда они захотят пить и вылезут из трюма, задраивают все люки. И НЕВАЖНО – УТОНУТ ОНИ ИЛИ ПОДОРВУТСЯ НА МИНАХ! Так и в моем случае – я придумал прием и написал на его основе несколько запросов для решения известных всем задач. А будут ли исправляться найденные ошибки или списываться найденные аналоги при этом неважно. Вспомните про тараканов – может быть, по ним ударит ракетный крейсер! Статья называется не «разработка высоконагруженной системы для контроля и исправления ошибок зацикливания в ориентированных графах большой размерности». Она называется «Уровни, глубина, прародители, циклы и аналоги ЗАПРОСОМ» и речь идет о ЗАПРОСЕ. Вы сами сузили метод до контроля циклов, присоединили задачу исправления ошибок, надумали ситуацию высокой интенсивности и параллелизма исправления ошибок и огорчились.
Далее, при чем здесь платформа 1С? Прием с тем же успехом можно реализовать в виде RCTE на SQL. Возможно, если бы sql.ru был бы таким же «нарядным» как Инфостарт, я бы предлагал прием там.
Так что не огорчайтесь! Смотрите: весна, все цветет, солнце, птички поют, кенгуру прыгают! – Радуйтесь! Вы скажете – при чем здесь Австралия! Вы притянули за уши надуманную задачу и расстроились. Я присоединил за уши Австралию и обрадовался! Чувствуете разницу? Так что больше позитива – больше креатива! Успехов и вам!
# Ответить
71. ADirks 19.11.2012 07:20
(ildarovich) Есть такая категория людей, которым очень нужно время от времени говорить кому-нибудь "ты тупой неудачник". И что бы ты ни написал, всё равно ты неудачник и лошара. Не обращай внимания.
Нормальные же люди взяли на заметку, и при случае применят без криков.
Ответили: (73)
# Ответить
72. DAnry 29.12.2012 12:14
Очень интересно и полезно. В некоторых случаях может сэкономить кучу времени. Премного благодарен автору.
# Ответить
73. insurgut 06.09.2013 15:46
(71) ADirks, зато от таких людей есть очень хороший плюс - они постоянно побуждают тебя двигаться дальше, познавать, изучать, разрабатывать новые идеи :)
# Ответить
74. wildhog 25.02.2014 20:25
...
Ответили: (76)
# Ответить
75. wildhog 25.02.2014 20:28
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| 1 КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ЭтоГруппа = Истина
|ИТОГИ ПО
| Номенклатура.Родитель.Ссылка ИЕРАРХИЯ";
РезультатЗапроса = Запрос.Выполнить();

Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);

МаксимальныйУровень = 0;

МассивСтрок = Дерево.Строки.НайтиСтроки(Новый Структура("Ссылка", NULL), Истина);
Для каждого СтрокаДерева Из МассивСтрок Цикл
Уровень = СтрокаДерева.Уровень();
Если МаксимальныйУровень < Уровень Тогда
МаксимальныйУровень = Уровень;
КонецЕсли;
КонецЦикла;

МаксимальныйУровень = МаксимальныйУровень + 1;
Ответили: (76) (80)
+ 1 [ Alien_job; ]
# Ответить
76. wildhog 25.02.2014 20:34
Прошу прощения за (74) (75). Нажимал "просмотр" - а вышел ответ...

Что собственно хотел сказать.
Возникла задача определить максимальный уровень группы справочника "Номенклатура", не важно есть в ней элементы, или нет.

В итоге вышло (75).
У нас в справочнике "Номенклатура" - ~200К элементов, ~3,5К групп.
На этих данных функция "ГлубинаИерархии" "работала" 2,5 минуты (база тестовая, файловая).
Предлагаемый мной вариант - меньше 5 секунд.

Т.е разница на порядок как минимум. Тестировать более строго пока нет возможности.
Ответили: (77)
# Ответить
77. ildarovich 25.02.2014 23:21
(76) Вообще я не претендую на то, что предложенный метод будет всегда и во всем лучшим. Его утяжеляет то, что он на промежуточных этапах строит все возможные связи в графе. А также то, что временные таблица не индексированы. Нужно, кстати, попробовать тут соединение на основе сортировки слиянием (то есть объединить и сгруппировать) - должно получаться быстрее. Но запрос будет более громоздким, а я здесь стремился к простоте и изяществу.

Но все же, чтобы соревнование было честным, Вам нужно поставить условие

Номенклатура.ЭтоГруппа = Истина

и в мой запрос тоже. В пролог.

Пролог = "ВЫБРАТЬ Родитель НачалоДуги, Ссылка КонецДуги ПОМЕСТИТЬ ЗамыканияДлины1 ИЗ Справочник.Номенклатура
| ГДЕ Родитель <> Значение(Справочник.Номенклатура.ПустаяСсылка) И Ссылка.ЭтоГруппа
| ОБЪЕДИНИТЬ ВЫБРАТЬ Ссылка, Ссылка ИЗ Справочник.Номенклатура;";

Сообщите, пожалуйста, результат.

И еще, раз Вы заинтересовались, хотел еще раз подчеркнуть факт, что приведенные функции приведены как функции для примера. Я считал, что построенные запросы будут в виде текстов использоваться внутри других запросов. Чтобы их результаты могли обрабатываться дальше. Я как-то это недостаточно ясно выразил в статье, судя по стандартной реакции читателей.
Ответили: (78)
# Ответить
78. wildhog 26.02.2014 10:25
(77) Тут и соревнования то никакого быть не может. В данной задаче работа с ссылками убивает все.
Я не собирался устраивать соревнования, только хотел поделиться придуманным мной велосипедом. На целую статью наверное маловато текста, а как комментарий/дополнение к вашей публикации - вполне.

Попробовал ваш вариант с ограничением по группам - значительно лучше, 20с
Ответили: (79)
# Ответить
79. ildarovich 26.02.2014 11:30
(78) ОК, понял. За результат спасибо, однако я допустил неточность, забыв про условие во второй половине запроса.

Пролог = "ВЫБРАТЬ Родитель НачалоДуги, Ссылка КонецДуги ПОМЕСТИТЬ ЗамыканияДлины1 ИЗ Справочник.Номенклатура
| ГДЕ Родитель <> Значение(Справочник.Номенклатура.ПустаяСсылка) И Ссылка.ЭтоГруппа
| ОБЪЕДИНИТЬ ВЫБРАТЬ Ссылка, Ссылка ИЗ Справочник.Номенклатура И Ссылка.ЭтоГруппа;";

Также взглянул на Ваш код. Возможно, Вам понравится использовать конструкцию, которую использую в этом случае я:

Для каждого СтрокаДерева Из МассивСтрок Цикл
МаксимальныйУровень = МАКС(МаксимальныйУровень, СтрокаДерева.Уровень())
КонецЦикла;
Ответили: (80) (86)
# Ответить
80. wildhog 26.02.2014 13:25
(79) И это правильный ответ ) 7 секунд. Только скорее всего не И Ссылка.ЭтоГруппа, а ГДЕ Ссылка.ЭтоГруппа
Уточняю, (75) - 1 секунда.
Про решение через МАКС спс)
# Ответить
81. Taktic 06.03.2014 17:35
Не могу понять что за параметр "МаксимальнаяДлинаПути" в каждой функции? Откуда он берется?
Ответили: (82)
# Ответить
82. ildarovich 07.03.2014 02:15
(81) Это оценка максимальной длины пути в графе. Для отношения иерархии в справочнике длина пути никогда не может быть больше числа элементов, например. Но, как правило, можно определить это число "из соображений здравого смысла", установив, например, что в справочнике не будет больше 1000 уровней.
# Ответить
83. ildarovich 08.04.2014 14:04
Обещанные в конце статьи "две интереснейших задачи-примеры" можно посмотреть в публикации Определение кратчайших путей, критических путей одним запросом.
# Ответить
84. prodines 25.04.2014 13:20
Функция ГлубинаИерархии(ИмяСправочника, МаксимальнаяДлинаПути) как раз и вычисляет "МаксимальнаяДлинаПути". Тогда чему же равно значение "МаксимальнаяДлинаПути", передаваемое в эту функцию?

ЗЫ Не заметил, что ответ приведен двумя постами выше. Но задать МаксимальнаяДлинаПути = 1000 неразумно, т.к. столь большое значение снизит производительность функции. Получается, надо "на глазок" задавать достаточно-реалистичное значение этого параметра (слегка с запасом).
# Ответить
85. teriban 12.06.2014 15:15
Интересная статья, даже почти разобрался :)
Тут, в примере:
Эпилог = "ВЫБРАТЬ КОЛИЧЕСТВО(НачалоДуги) - 1 Предок, КонецДуги Потомок ИЗ ЗамыканияДлины#2 СГРУППИРОВАТЬ ПО КонецДуги";

можно определить последний уровень, а вот можно ли как-то получить номера уровней всех групп?

Например:
Предок Потомок Уровень
Группа1 | Элемент | 1
Группа2 | Элемент | 2
Группа3 | Элемент | 3
Группа4 | Элемент | 4
Ответили: (86)
# Ответить
86. ildarovich 16.06.2014 11:02
(85) Странный вопрос. Потому что код, который вами же приведен, делает именно то, что вы хотите - определяет номера уровней всех элементов (и групп, естественно тоже). Это раздел 1 статьи. Там и скриншот результата работы функции приведен, где видно, что определяются именно уровни.
Ну а если затруднения в том, чтобы отобрать группы, то посмотрите начало запроса в комментарии (79). Там в два места добавлена проверка Ссылка.ЭтоГруппа. Таким тогда и должен быть пролог запроса.
Ответили: (87)
# Ответить
87. teriban 14.07.2014 23:39
(86) ildarovich, может я что-то не понял (или не так написал) но, на мой взгляд:
приведенный код позволяет определить уровень группы в который входит элемент. Для моей задачи нужно знать уровень группы в который входит элемент, а также уровень группы в которую входит группа в которую входит элемент :) и т. д.
Ответили: (88)
# Ответить
88. ildarovich 15.07.2014 00:34
(87) teriban, из первоначальной формулировки вашего вопроса было непонятно, но если теперь формулировка такая
а вот можно ли как-то получить номера уровней всех групп? (включающих заданный элемент)
то для этого нужно дополнительно из всех групп и элементов, уровни которых определены в примере 1, отобрать те, которые включают данный элемент, то есть который является их потомком.
Эпилог = "ВЫБРАТЬ УровниПредков.Уровень, УровниПредков.Предок 
|Из (ВЫБРАТЬ КОЛИЧЕСТВО(НачалоДуги) - 1 Уровень, КонецДуги Предок 
|ИЗ ЗамыканияДлины#2 
|СГРУППИРОВАТЬ ПО КонецДуги) КАК УровниПредков 
|СОЕДИНЕНИЕ ЗамыканияДлины#2 КАК Связи 
|ПО УровниПредков.Предок = Связи.НачалоДуги 
|И Связи.КонецДуги = &ЗаданныйЭлемент";
...Показать Скрыть
...как-то так...
+ 1 [ teriban; ]
# Ответить
89. kentavr27 06.04.2015 20:34
(0) Замечательные алгоритмы, за которые огромное спасибо.
Только вот требуется помощь. Долгое время уже кручу и так и сяк, не могу найти нормального решения. Может подмогнете?

Исходные данные:
Иерархический справочник с подчинением элементам. Глубина неизвестна (предположим до 10 уровней). Длина веток может быть любой.

Задача
Получить Список элементов справочника с заданным родителем. В выборку должны попасть только те элементы у которых хотя бы один потомок, находящийся на самом нижнем уровне удовлетворяет условию типа Элемент.Свойство=&МоеСвойство
Ответили: (90)
# Ответить
90. ildarovich 07.04.2015 15:26
(89) kentavr27, предлагается такой алгоритм:
1) по структуре справочника получаете таблицу пар предок-потомок. Это делается так же, как в любом из примеров 1-3.
2) теперь ставите условие:
-) предок должен быть равным заданному. Таким образом отбираете все узлы, транзитивно входящие в заданный.
-) потомок должен иметь заданное значение свойства.
То есть меняется только Эпилог запроса.
В результате запрос будет иметь вид:
ВЫБРАТЬ
	Номенклатура.Родитель КАК НачалоДуги,
	Номенклатура.Ссылка КАК КонецДуги
ПОМЕСТИТЬ ЗамыканияДлины1
ИЗ
	Справочник.Номенклатура КАК Номенклатура
ГДЕ
	Номенклатура.Родитель <> ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	Номенклатура.Ссылка,
	Номенклатура.Ссылка
ИЗ
	Справочник.Номенклатура КАК Номенклатура
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПерваяДуга.НачалоДуги,
	ВтораяДуга.КонецДуги
ПОМЕСТИТЬ ЗамыканияДлины2
ИЗ
	ЗамыканияДлины1 КАК ПерваяДуга
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины1 КАК ВтораяДуга
		ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПерваяДуга.НачалоДуги,
	ВтораяДуга.КонецДуги
ПОМЕСТИТЬ ЗамыканияДлины4
ИЗ
	ЗамыканияДлины2 КАК ПерваяДуга
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины2 КАК ВтораяДуга
		ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПерваяДуга.НачалоДуги,
	ВтораяДуга.КонецДуги
ПОМЕСТИТЬ ЗамыканияДлины8
ИЗ
	ЗамыканияДлины4 КАК ПерваяДуга
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины4 КАК ВтораяДуга
		ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПерваяДуга.НачалоДуги,
	ВтораяДуга.КонецДуги
ПОМЕСТИТЬ ЗамыканияДлины16
ИЗ
	ЗамыканияДлины8 КАК ПерваяДуга
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины8 КАК ВтораяДуга
		ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ЗамыканияДлины16.КонецДуги КАК Элемент
ПОМЕСТИТЬ Подчиненные
ИЗ
	ЗамыканияДлины16 КАК ЗамыканияДлины16
ГДЕ
	ЗамыканияДлины16.НачалоДуги = &ВыбНоменклатура
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	ЗамыканияДлины16.НачалоДуги КАК Элемент
ПОМЕСТИТЬ Содержательные
ИЗ
	ЗамыканияДлины16 КАК ЗамыканияДлины16
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
		ПО ЗамыканияДлины16.КонецДуги = ЗначенияСвойствОбъектов.Объект
			И (ЗначенияСвойствОбъектов.Свойство = &ВыбСвойство)
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	Подчиненные.Элемент
ИЗ
	Подчиненные КАК Подчиненные
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Содержательные КАК Содержательные
		ПО Подчиненные.Элемент = Содержательные.Элемент
...Показать Скрыть
Будут обрабатываться до 16-ти уровней в справочнике.
Последние три запроса легко объединяются в один с двумя соединениями.
Ответили: (91)
# Ответить
91. kentavr27 09.04.2015 14:43
(90) ildarovich, спасибо за отклик. Возможно я что-то не так сделал... если можно, давайте рассмотрим на живом запросе.
У меня не верно выполняется след. условие
В выборку должны попасть только те элементы у которых хотя бы один потомок, находящийся на самом нижнем уровне удовлетворяет условию типа Элемент.Свойство=&МоеСвойство

Вместо "на самом нижнем уровне" в результат запроса попадает "на любом из нижележащих уровней"
Т.е. из дерева
Административные расходы........(НЕ свойство ОК)
.....|_____ Услуги связи........(свойство ОК)
..........|___ Интернет.........(НЕ свойство ОК)
..........|___ Мобильная связь..(НЕ свойство ОК)
..........|___ Почта............(НЕ свойство ОК)

В выборку с родителем "Административные расходы" попадает "Услуги связи", хотя ни один элемент последнего уровня Услуг связи не удовлетворяет условию.

Текст моего запроса:
ВЫБРАТЬ
	ФинансовыеОперации.Родитель КАК НачалоДуги,
	ФинансовыеОперации.Ссылка КАК КонецДуги
ПОМЕСТИТЬ ЗамыканияДлины1
ИЗ
	Справочник.ФинансовыеОперации КАК ФинансовыеОперации
//ГДЕ
//	ФинансовыеОперации.Родитель <> ЗНАЧЕНИЕ(Справочник.ФинансовыеОперации.ПустаяСсылка)

ОБЪЕДИНИТЬ

ВЫБРАТЬ
	ФинансовыеОперации.Ссылка,
	ФинансовыеОперации.Ссылка
ИЗ
	Справочник.ФинансовыеОперации КАК ФинансовыеОперации
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПерваяДуга.НачалоДуги,
	ВтораяДуга.КонецДуги
ПОМЕСТИТЬ ЗамыканияДлины2
ИЗ
	ЗамыканияДлины1 КАК ПерваяДуга
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины1 КАК ВтораяДуга
		ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПерваяДуга.НачалоДуги,
	ВтораяДуга.КонецДуги
ПОМЕСТИТЬ ЗамыканияДлины4
ИЗ
	ЗамыканияДлины2 КАК ПерваяДуга
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ЗамыканияДлины2 КАК ВтораяДуга
		ПО ПерваяДуга.КонецДуги = ВтораяДуга.НачалоДуги
;


////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ЗамыканияДлины4.КонецДуги КАК Элемент
ПОМЕСТИТЬ Подчиненные
ИЗ
	ЗамыканияДлины4 КАК ЗамыканияДлины4
ГДЕ
	ЗамыканияДлины4.НачалоДуги = &ВыбРодитель
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
	ЗамыканияДлины4.НачалоДуги КАК Элемент
ПОМЕСТИТЬ Содержательные
ИЗ
	ЗамыканияДлины4 КАК ЗамыканияДлины4
ГДЕ
	ЗамыканияДлины4.КонецДуги.МетодНачисления = &МетодНачисления
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	Подчиненные.Элемент
ИЗ
	Подчиненные КАК Подчиненные
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Содержательные КАК Содержательные
		ПО (Подчиненные.Элемент = Содержательные.Элемент
				И Подчиненные.Элемент.Родитель = &ВыбРодитель)
...Показать Скрыть

В чем здесь моя ошибка? (не считая оптимизации)
Ответили: (92)
# Ответить
92. ildarovich 09.04.2015 15:25
(91) kentavr27, ну да, то, что свойство будет у самого нижнего уровня, здесь никак не проверяется. Нужна еще одна проверка для "конца дуги" при формировании таблицы "содержательная".
ВЫБРАТЬ РАЗЛИЧНЫЕ
    ЗамыканияДлины4.НачалоДуги КАК Элемент
ПОМЕСТИТЬ Содержательные
ИЗ
    ЗамыканияДлины4 КАК ЗамыканияДлины4
ГДЕ
    ЗамыканияДлины4.КонецДуги.МетодНачисления = &МетодНачисления 
    И ЗамыканияДлины4.КонецДуги В (ВЫБРАТЬ НачалоДуги 
                                   ИЗ ЗамыканияДлины1 
                                   СГРУППИРОВАТЬ ПО НачалоДуги 
                                   ИМЕЮЩИЕ (Количество(*) = 1))
;
...Показать Скрыть
Код нужно еще проверить, но идея в том, что у "листьев" только одна исходящая дуга (замкнутая на себя)
Ответили: (93)
+ 1 [ kentavr27; ]
# Ответить
93. kentavr27 09.04.2015 15:52
(92) ildarovich, Да. То что нужно. Спасибо огромное. Осталось терь в голове это все упорядочить... :)
# Ответить
94. DeniNikitin (файл скачал) 11.06.2015 15:10
Для УПП 1.3.64.1 циклы не работают!!!
Ответили: (96)
# Ответить
95. DeniNikitin (файл скачал) 11.06.2015 15:21
Вот пример иерархии в справочнике спецификаций и сама спецификация
Ответили: (96)

Прикрепленные файлы:

Пример спецификации.jpg
# Ответить
96. ildarovich 11.06.2015 15:35
(94) (95) DeniNikitin, уточните, пожалуйста, как именно не работают, будем разбираться:
- ошибка выполнения? - тогда скриншрт пришлите
- не находит циклы? - тогда желателен скриншот не одной спецификации, а всех, входящих в цикл.
Ответили: (97)
# Ответить
97. DeniNikitin (файл скачал) 11.06.2015 18:03
(96) ildarovich,
Не заполняет вообще, скрин спецификаций из вашего запроса прикладываю или какой скрин вам нужен?

Прикрепленные файлы:

Скрин спецификаций.jpg
# Ответить
98. DeniNikitin (файл скачал) 11.06.2015 18:41
Ещё прикладываю файл excel со всем списком спецификаций из справочника!
Ответили: (99)

Прикрепленные файлы:

Спецификации.xls
# Ответить
99. ildarovich 11.06.2015 22:59
(98) DeniNikitin, спасибо, попробую разобраться на следующей неделе, но вы уверены, что в этом наборе спецификаций есть циклы активных спецификаций?
Ответили: (100)
# Ответить
100. DeniNikitin (файл скачал) 12.06.2015 07:49
(99) ildarovich,
По подробней как это проверить?
# Ответить
101. DeniNikitin (файл скачал) 12.06.2015 07:50
Если вы про то что изделие состоит из другиз изделий, то да! Например: Кисть состоит из бугеля и щетины, а бугель состоит из подшипника и ручки и.т.д.!
Ответили: (102)
# Ответить
102. ildarovich 13.06.2015 11:12
(101) DeniNikitin, назначение функции, приведенной в разделе 4 - определение ЦИКЛОВ в наборе активных спецификаций. Наличие циклов - это ОШИБКА, допущенная при вводе спецификаций. Эта ошибка приводит к зацикливанию расчетов потребностей в материалах в процессе разузлования или неточностям этих расчетов.
Цикл - это ситуация, когда
Кисть состоит из бугеля и щетины, а бугель состоит из подшипника и ручки и.т.д.!
где в "и т.д." есть спецификация, где ручка состоит из кисти (ошибочно), в результате образуется цикл через несколько спецификаций.
В большом наборе спецификаций обнаружить ошибку в виде цикла трудно. Решение из пункта 4 упрощает решение этой задачи. И если на вашем наборе данных обработка не находит циклов (ошибок), возможно, значит, что циклов (ошибок) в вашем наборе нет.
Ответили: (103)
# Ответить
103. DeniNikitin (файл скачал) 15.06.2015 18:09
(102) ildarovich,
Тогда понятно, я просто думал, что это функция позволить мне вернуть таблицу значений разобранную и по ней уже работать, а так всё равно писать надо будет!
# Ответить
104. Apatic 16.08.2015 14:33
Спасибо за статьи!
Очень интересно, действительно впечатляет.


А насчет максимальной глубины справочника, я, конечно, чувствую себя жутким быдлокодером, но всегда использовал что-то типа такого решения:


ВЫБРАТЬ
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Номенклатура.Ссылка) КАК Ссылка
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Родитель...n....Родитель = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)

Минус метода, что надо знать примерно возможную верхнюю границу количества родителей. Если с ней получаем 0, то затем количество родителей уменьшаем n на один до тех пор, пока результат запроса не станет равен 0.

Если значение верхней границы очень уж высоко, то делать вручную неудобно и тогда этот запрос пихаем в обработку, уменьшая n (количество родителей) в запросе программно.
Насчет быстродействия не знаю, но для моих задач всегда быстро срабатывало.
# Ответить
105. hornet_X 18.11.2015 15:44
ildarovich,
спасибо огромное за статью)))
# Ответить
Внимание! За постинг в данном форуме $m не начисляются.
Внимание! Для написания сообщения необходимо авторизоваться
Текст сообщения*
Прикрепить файл