Имя: Пароль:
1C
1С v8
СОЕДИНИТЬ ПО "В ИЕРАРХИИ" - решено
,
0 Вуглускр1991
 
07.10.13
20:37
Были темы
v8: В запросе связать таблицу номенклатуры с таблицей ее корневых родителей
v8: Запрос иерархия
v8: Справочник - ссылка и родитель верхнего уровня
Ещё нарыть можно, при желании. Думаю многие поймут, почему нельзя соединять две таблицы по условию реквизит Таблицы1 В ИЕРАРХИИ реквизит Таблицы2.
Думаю многие, кто знает SQL этого не поймут. А кто знает ещё и CTE задумаются о кроссплатформенности CTE для DB2 oracle и postgre.
Мне миста много помогла в оперативной работе, спасибо мистяне.
Если сочтете годным такой способ решения проблемы - берите.
Добавляем регистр сведений "ИерархияНоменклатуры"
с измерениями:
"НоменклатураГруппа" - номенклатура
"НоменклатураРодитель" - номенклатура
и можно ресурс
"УровеньВИерархии" - число
Добавляем подписку на событие
"АктуализироватьЛинейкуГруппНоменклатуры"
Источник: "СправочникОбъект.Номенклатура"
Событие:  "ПриЗаписи"
Обработчик: в отдельном серверном привилегированном модуле
Процедура АктуализироватьЛинейкуГруппНоменклатурыПриЗаписи(Источник, Отказ) Экспорт
    // Вставить содержимое обработчика.
    Если Источник.ЭтоГруппа Тогда
        РегистрыСведений.ИерархияНоменклатуры.АктуализироватьЛинейкуГрупп();
    КонецЕсли;
КонецПроцедуры
Затем, добавляем в модуль менеджера регистра три процедуры:
Процедура ЗаписатьГруппу(СтруктураСКлючами)
    
    НаборЗапРега = СоздатьНаборЗаписей();
    
    НаборЗапРега.Отбор.НоменклатураГруппа.Установить(СтруктураСКлючами.НоменклатураГруппа);
    НаборЗапРега.Отбор.НоменклатураРодитель.Установить(СтруктураСКлючами.НоменклатураРодитель);
    
    НаборЗапРега.Прочитать();
    
    НаборЗапРега.Записывать = Истина;
    
    НоваЗапа = 0;
    Если НаборЗапРега.Количество() = 0 Тогда
        НоваЗапа = НаборЗапРега.Добавить();
    Иначе
        НоваЗапа = НаборЗапРега[0];
        Если НоваЗапа.УровеньВИерархии = СтруктураСКлючами.УровеньВИерархии Тогда
            Возврат;
        КонецЕсли;
    КонецЕсли;
    
    ЗаполнитьЗначенияСвойств(НоваЗапа,СтруктураСКлючами);
    НаборЗапРега.УстановитьАктивность(Истина);
    
    НаборЗапРега.Записать();
КонецПроцедуры

Процедура УдалитьГруппу(СтруктураСКлючами)
    
    НаборЗапРега = СоздатьНаборЗаписей();
    
    НаборЗапРега.Отбор.НоменклатураГруппа.Установить(СтруктураСКлючами.НоменклатураГруппа);
    НаборЗапРега.Отбор.НоменклатураРодитель.Установить(СтруктураСКлючами.НоменклатураРодитель);
    
    НаборЗапРега.Прочитать();
    
    НаборЗапРега.Записывать = Истина;
    НаборЗапРега.Очистить();
    
    НаборЗапРега.Записать();
КонецПроцедуры


Процедура АктуализироватьЛинейкуГрупп() Экспорт
    
    ЗапорНах = Новый Запрос;
    ЗапорНах.Текст = "ВЫБРАТЬ
                     |    Номенклатура.Ссылка КАК НоменклатураГруппа,
                     |    Номенклатура.Родитель КАК НоменклатураРодитель,
                     |    0 КАК УровеньВИерархии
                     |ИЗ
                     |    Справочник.Номенклатура КАК Номенклатура
                     |ГДЕ
                     |    Номенклатура.ЭтоГруппа = ИСТИНА
                     |    И Номенклатура.ПометкаУдаления = ЛОЖЬ";
    ТабаРодов = ЗапорНах.Выполнить().Выгрузить();
    
    СтрокиУдалить = Новый Массив;
    
    ПоследИнда = ТабаРодов.Количество() - 1;
    СчИнда = 0;
    Для СчИнда = 0 По ПоследИнда Цикл
        
        ТекаСтро = ТабаРодов[СчИнда];
        
        Если ТекаСтро.НоменклатураРодитель.Пустая() Тогда
            СтрокиУдалить.Добавить(ТекаСтро);
        Иначе
            ТекаСтро.УровеньВИерархии = ТекаСтро.НоменклатураРодитель.Уровень();
        КонецЕсли;
        
        ЕщёРодитель = ТекаСтро.НоменклатураРодитель.Родитель;
        Пока Не ЕщёРодитель.Пустая() Цикл
            
            НоваСтро = ТабаРодов.Добавить();
            НоваСтро.НоменклатураГруппа   = ТекаСтро.НоменклатураГруппа;
            НоваСтро.НоменклатураРодитель = ЕщёРодитель;
            НоваСтро.УровеньВИерархии     = ЕщёРодитель.Уровень();
            ЕщёРодитель = ЕщёРодитель.Родитель;
        КонецЦикла;
        
        СамоСтро = ТабаРодов.Добавить();
        СамоСтро.НоменклатураГруппа   = ТекаСтро.НоменклатураГруппа;
        СамоСтро.НоменклатураРодитель = ТекаСтро.НоменклатураГруппа;
        СамоСтро.УровеньВИерархии     = ТекаСтро.НоменклатураГруппа.Уровень();
    КонецЦикла;
    
    Для Каждого Эл Из СтрокиУдалить Цикл
        
        ТабаРодов.Удалить(Эл);
    КонецЦикла;
    
    ТабаРодов.Сортировать("НоменклатураГруппа Возр,УровеньВИерархии Возр,НоменклатураРодитель Возр",);
    
    Для Каждого Стр Из ТабаРодов Цикл
        
        ЗаписатьГруппу(Стр);
    КонецЦикла;
    
    ЗапорНах.Текст = "ВЫБРАТЬ
                     |    ТабаРодов.НоменклатураГруппа,
                     |    ТабаРодов.НоменклатураРодитель,
                     |    ТабаРодов.УровеньВИерархии
                     |ПОМЕСТИТЬ ТАБАРОДОВ
                     |ИЗ
                     |    &ТабаРодов КАК ТабаРодов
                     |;
                     |
                     |////////////////////////////////////////////////////////////////////////////////
                     |ВЫБРАТЬ
                     |    ИерархияНоменклатуры.НоменклатураГруппа,
                     |    ИерархияНоменклатуры.НоменклатураРодитель,
                     |    ИерархияНоменклатуры.УровеньВИерархии
                     |ИЗ
                     |    РегистрСведений.ИерархияНоменклатуры КАК ИерархияНоменклатуры
                     |        ЛЕВОЕ СОЕДИНЕНИЕ ТАБАРОДОВ КАК ТАБАРОДОВ
                     |        ПО ИерархияНоменклатуры.НоменклатураГруппа = ТАБАРОДОВ.НоменклатураГруппа
                     |            И ИерархияНоменклатуры.НоменклатураРодитель = ТАБАРОДОВ.НоменклатураРодитель
                     |ГДЕ
                     |    ТАБАРОДОВ.НоменклатураГруппа ЕСТЬ NULL ";
    ЗапорНах.УстановитьПараметр("ТабаРодов",ТабаРодов);
    ТабаНеактуальные = ЗапорНах.ВыполнитьПакет()[1].Выгрузить();
    
    Для Каждого Стр Из ТабаНеактуальные Цикл
    
        УдалитьГруппу(Стр);
    КонецЦикла;
КонецПроцедуры
После чего можно заменять конструкциею "В ИЕРАРХИИ" внутри запроса
вот так:
"ВЫБРАТЬ
|        Номенклатура.Ссылка,
|        ИерархияНоменклатуры.НоменклатураРодитель,
|        ИерархияНоменклатуры.УровеньВИерархии
|    ИЗ
|        Справочник.Номенклатура КАК Номенклатура
|    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ИерархияНоменклатуры КАК ИерархияНоменклатуры
|    ПО Номенклатура.Родитель = ИерархияНоменклатуры.НоменклатураГруппа"
1 ProProg
 
07.10.13
20:39
Ставлю два - за регистр.
Это не вариант.
2 Fragster
 
модератор
07.10.13
20:41
на самом деле если бы 1с незажмотились на нормальное физическое хранение иерархии (правое и левое значение дерева), то условие соединения выглядело бы как МЕЖДУ
3 Вуглускр1991
 
07.10.13
20:42
(1) Я не насилую. Мне подошло. Улучшить можешь?
4 МихаилМ
 
07.10.13
20:42
5 Fragster
 
модератор
07.10.13
20:42
для варианта с регистром - это выглядело бы как Ссылка, левое значение, правое значение.
6 extrim-style
 
07.10.13
20:42
имена переменных внушают
7 Вуглускр1991
 
07.10.13
20:43
(6) Копировал из боевой конфы, не причесал :)
8 Fragster
 
модератор
07.10.13
21:12
ну и да - есть еще волшебная СКД
9 Fragster
 
модератор
07.10.13
21:12
10 ProProg
 
07.10.13
21:17
Кто мне пояснит глубокий смысл сего кода


"ВЫБРАТЬ
|        Номенклатура.Ссылка,
|        ИерархияНоменклатуры.НоменклатураРодитель,
|        ИерархияНоменклатуры.УровеньВИерархии
|    ИЗ
|        Справочник.Номенклатура КАК Номенклатура
|    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ИерархияНоменклатуры КАК ИерархияНоменклатуры
|    ПО Номенклатура.Родитель = ИерархияНоменклатуры.НоменклатураГруппа"
11 Вуглускр1991
 
07.10.13
21:34
(10) Это пример использования в чистом виде, без смысловой нагрузки.
Во многих конфигурациях через группы созданы политики, максимальный приоритет имеет политика записанная для непосредственного родителя.
Вся номенклатура из группы товары учитывается на 41.01
Однако из папки "цветочные магазины НТТ" на 41.11
Мы знаем как в БП такое сотворить.
Тогда можно построить таблицу
"горшок ВАЛЕНОК" - "цветочные магазины НТТ" - 2 - 41.11
"горшок ВАЛЕНОК" - "товары" - 1 - 41.01
Где 2 и 1 соответственно уровни родителей "горшка ВАЛЕНКА"
Поэтому взяв максимум мы получим результирующую политику
учет на 41.11 и все в одном запросе.
12 Defender aka LINN
 
07.10.13
23:24
(10) Тебе - бесполезно.
(0) Еще можно для каждой группы определить диапазон идентификаторов. Т.е., группы верхнего уровня - от 1 до 10000, от 10001 до 20000 и т.д., к примеру. Вложенная в первую группу - от 1 до 1000, вложенная в нее - от 1 до 100. Ну и тогда тупо по вхождению в интервал.
13 Classic
 
07.10.13
23:28
(12)
Угу. Фиксированная кодировка групп номенклатуры спасает
14 ProProg
 
08.10.13
00:46
(11) для этого регистр сведений специальный не нужен.
Это разовая задача в каких то допилках и решается элементарнейшим способом!
15 MiniMuk
 
08.10.13
05:14
(0) Если уровень родства вести в самом справочнике?
16 Лодырь
 
08.10.13
05:32
(14) Расскажи мне про элементарный способ получения такого рода информации в запросе.
17 Вуглускр1991
 
08.10.13
08:42
(14) Ещё одна разовая задача: получить сопоставление элемента номенклатуры и его самого верхнего родителя.
18 Fragster
 
модератор
08.10.13
09:19
(17)->(9)
19 ProProg
 
08.10.13
09:22
(17) а такое вообще как два пальца. в СКД при работе с запросами в доступных полях есть группа Системный полей, к которым моджно обращаться с названием Уровень и Уровень в группе.

В типовых есть масса отчетов где отчеты построены по кнокретному уровню иерархии и даже с номенклатурой.
20 Вуглускр1991
 
08.10.13
09:26
(18) Спасибо, я как ещё одну задачу плюсом.
Есть два вида языков, одни постоянно ругают, а вторыми никто не пользуется.