1с как найти родителя верхнего

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

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

РодительСсылка = СправочникСсылка.Родитель.Родитель.Родитель; 

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

Определить самого верхнего родителя

Универсальную функцию для определения самого верхнего родителя элемента можно реализовать с помощью встроенного языка программирования. Функции на вход подаётся ссылка на элемент иерархического справочника, а возвращается ссылка на самую верхнюю группу.

Функция ПолучитьРодителя(СправочникСсылка)Пока НЕ СправочникСсылка.Родитель.Пустая() Цикл
СправочникСсылка = СправочникСсылка.Родитель;
КонецЦикла;Возврат СправочникСсылка;КонецФункции

Определить самого верхнего родителя с использованием запроса

В запросе можно найти родителей элемента обратившись к свойствам через точку или с помощью левого соединения. Данные методы не универсальны, так как уровень вложенности фиксирован в запросе. Такой метод подходит, когда заранее известно количество уровней иерархического справочника. Функция на вход принимает ссылку на элемент иерархического справочника, а возвращает ссылку на группу N-уровня.

Функция ПолучитьРодителейЗапросе(СправочникСсылка)

Запрос

= Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Справочник1.Родитель.Родитель.Родитель КАК Родитель
|ИЗ
| Справочник.Справочник1 КАК Справочник1
|ГДЕ
| Справочник1.Ссылка = &Справочник1Ссылка"
;

Запрос

.УстановитьПараметр("Справочник1Ссылка", СправочникСсылка);
Результат = Запрос.Выполнить();Если НЕ Результат.Пустой() Тогда

Выборка

= Результат.Выбрать();
Выборка.Следующий();
Возврат Выборка.Родитель;КонецЕсли;Возврат Справочники.Справочник1.ПустаяСсылка();КонецФункции

КАК у элемента справочника быстро найти самого верхнего родителя?

Я
   Vika64

04.02.09 — 15:14

вопрос, собственно в теме

   gr13

1 — 04.02.09 — 15:15

Пока ЗначениеЗаполнено(ВыбСправочник.Родитель) Цикл
ВыбСправочник = ВыбСправочник.Родитель;
КонецЦикла

   Vika64

2 — 04.02.09 — 15:17

Спасибо, попробую.

   almar

3 — 04.02.09 — 15:21

а в запросе?

   gr13

4 — 04.02.09 — 15:22

2… варианта… есть тебе какой попроще и подурацкей, или посложнее и покрасивей?

   AndOne

5 — 04.02.09 — 15:25

правильный.

   H A D G E H O G s

6 — 04.02.09 — 15:26

(4) Желательно для неограниченного по иерархии справочника

   Sadovnikov

7 — 04.02.09 — 15:35

Для семерки:

Set NoCount On

Declare @элТовар Char(9)

Set @элТовар = ‘   2IW   ‘

While 1 = 1 Begin

   Select

       @элТовар = ParentID

   From

       спрНоменклатура

   Where

       ID = @элТовар And ParentID != ‘     0   ‘

   IF @@RowCount = 0 Break

End

Select @элТовар

Для восьмерки — по аналогии.

   H A D G E H O G s

8 — 04.02.09 — 15:36

(7) Нет в восьмерке в запросах переменных.

   Sadovnikov

9 — 04.02.09 — 15:37

(8) Сочуствую, конечно, восьмерке… Но, то же самое ADO еще никто не отменял :)

   megalodon

10 — 04.02.09 — 15:38

для реально неограниченного количества уровней в запросе не получить. но если точно нать, что реальное количество уровней иерархии например не больше пяти — тогда запросто.

   NcSteel

11 — 04.02.09 — 15:39

В запросе быстрее. Имхо

   Sadovnikov

12 — 04.02.09 — 15:39

(10) Как это не получить? См. (7).

   megalodon

13 — 04.02.09 — 15:40

(12) я про запросы 1С 8.х. Там к сожалению ни циклов ни рекурсии нет.

   tsr

14 — 04.02.09 — 15:40

(6) А если в Иерархии с условием Родитель=Справочник.ПустоеЗначение ?

   Sadovnikov

15 — 04.02.09 — 15:40

(13) Тогда см (9)

:)

   megalodon

16 — 04.02.09 — 15:42

(15) ну тогда скинь мне АДО драйвер для файловой восьмерки умнег :-)

   NcSteel

17 — 04.02.09 — 15:42

ВЫБРАТЬ
   Номенклатура.Ссылка КАК Ссылка

    ИЗ
   Справочник.Номенклатура КАК Номенклатура
ГДЕ
   Номенклатура.Ссылка = &Ссылка
ИТОГИ ПО
   Ссылка ТОЛЬКО ИЕРАРХИЯ

А такой способ не устраивает?

   gr13

18 — 04.02.09 — 15:42

(5) правильного не знаю.
(6) если для ограниченного, то можно так

ВЫБОР
   КОГДА РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации.Родитель = ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка)
       ТОГДА РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации.Родитель
   ИНАЧЕ ВЫБОР
           КОГДА РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации.Родитель.Родитель = ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка)
               ТОГДА РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации.Родитель.Родитель
           ИНАЧЕ РаботникиОрганизацийСрезПоследних.ПодразделениеОрганизации.Родитель.Родитель.Родитель
       КОНЕЦ
КОНЕЦ

   Sadovnikov

19 — 04.02.09 — 15:42

(16) А нефиг пользоваться левыми продуктами. Восьмерка, файловая. На до же…

   NiXeR

20 — 04.02.09 — 15:43

Запрос = Новый Запрос;

Запрос.Текст =

«ВЫБРАТЬ

|    Номенклатура.Ссылка КАК Ссылка

|ИЗ

|    Справочник.Номенклатура КАК Номенклатура

|ГДЕ

|    Номенклатура.Ссылка = &Ссылка

|ИТОГИ ПО

|    Ссылка ТОЛЬКО ИЕРАРХИЯ»;

Запрос.УстановитьПараметр(«Ссылка»,МояСсылка);

Выборка = Запрос.Выполнить().Выбрать();

Выборка.Следующий();

ВерхнийУровень = Выборка.Ссылка;

   Sadovnikov

21 — 04.02.09 — 15:43

(18) Опупеть… «Здраствуйте, тормоза!!!»

   NcSteel

22 — 04.02.09 — 15:43

(20) Баян

   gr13

23 — 04.02.09 — 15:43

(17) угу, что-то вроде. потом можно попробовать прикрутить по левому соединению другую таблицу. Но у меня в правилах не получилось указать В Иерархии

   gr13

24 — 04.02.09 — 15:44

(21) какие тормоза))) нет никаких тормозов. Я как вариант привел, который будет работать, предложи лучше

   megalodon

25 — 04.02.09 — 15:45

(20) не годится, потому что результат нельзя использовать например в подзапросе.

   ATI

26 — 04.02.09 — 15:46

насчет семерки: как-то Рупор приводил такой код :

ВерхнийРодитель=ЗначениеИзСтрокиВнутр(Шаблон(«[ЗначениеВСтрокуВнутр(Спр»+СтрЗаменить(Формат(«»,»С»+(Спр.Уровень()-1)),» «,».Родитель»)+»)]»));

:)

   NcSteel

27 — 04.02.09 — 15:46

(25) Можно, выгружайте в Таблицу, дальше Временные таблицы

   megalodon

28 — 04.02.09 — 15:46

(19) ОК. В монопольном режиме 1С 8.х твое АДО будет работать? :-)

   ATI

29 — 04.02.09 — 15:46

+26 вот где красота и изящество :D

   NcSteel

30 — 04.02.09 — 15:47

(0) Логичнее использовать не Иерархию справочника, а например Номенклатурные группы

   Sadovnikov

31 — 04.02.09 — 15:49

(26) Это да.. Тот еще извращенец :) «Извращенец» в данном случае — в хорошем смысле.

(28) Мое ODBC — будет. А ваше восьмерошное ADO — нет, конечно :)

   megalodon

32 — 04.02.09 — 15:49

(27) тогда это ничем не отличается от получения главного родителя в 1С-ком коде.

   Sadovnikov

33 — 04.02.09 — 15:50

(24) А засветика что скуль при таком запросе выполнит?

   Сергей-ХХХ

34 — 04.02.09 — 15:51

А вообще у товара есть  полный код, который косухами разделен. Типа

ИскомыйРодитель =  спр.НайтиПоКоду(Лев(товар.полныйкод,1,Найти(товар.полныйкод,»/»)-1))

   NcSteel

35 — 04.02.09 — 15:51

Да не лучше, но запрос быстрее + методично правильнее.

   Sadovnikov

36 — 04.02.09 — 15:52

(34) Ай молодца! Меня практически каждый твой пост радует! Зайди-ка на закладочку «Нумерация» в свойствах справочника.

   Сергей-ХХХ

37 — 04.02.09 — 15:54

(36) По коду будет искатся верхний уровень, а нам больше ничего и не надо ))) Меня твои посты тоже радуют глупостью…

   Sadovnikov

38 — 04.02.09 — 15:55

(37) У тебя СП украли? Почитай

«<Родитель> (необязательный)

Тип: СправочникСсылка. Родитель, в пределах которого нужно выполнять поиск. Если не указан, то поиск будет проводиться во всем справочнике. «

   Сергей-ХХХ

39 — 04.02.09 — 15:56

(38) НайтиПоКоду(<Код>, <Поиск по полному коду>, <Родитель>, <Владелец>)

В чем проблема?

   NcSteel

40 — 04.02.09 — 15:57

(37) Юморной однако.

Хотя в 7.7 есть возможность получить «полный код» справочника через «»

   Sadovnikov

41 — 04.02.09 — 15:57

(39) Еще раз внимательно (38) прочитай. А потом все-таки загляни на закладочку «Нумерация».

   Сергей-ХХХ

42 — 04.02.09 — 15:57

(40) В 8.х тоже

   NcSteel

43 — 04.02.09 — 15:58

(39) Ты предлогаешь в элементе справочника хранить поле с програмно записанным путем к родителю, имхо это не правильно

   Сергей-ХХХ

44 — 04.02.09 — 15:58

СправочникСсылка.<Имя справочника> (CatalogRef.<Имя справочника>)

ПолныйКод (FullCode)

Синтаксис:

ПолныйКод()

Возвращаемое значение:

Тип: Строка. Строка, включающая код элемента и коды всех вышестоящих элементов.

Коды выводятся слева направо, начиная с самого верхнего уровня, разделяются символом «/».

Описание:

Получает код элемента справочника с учетом кодов всех вышестоящих элементов.

Пример:

Сообщить(«Полный код данного элемента: » +

         СсылкаНаЭлемент.ПолныйКод());

   NcSteel

45 — 04.02.09 — 15:58

(42) Нельзя, только програмно. посмотри свой код и заметишь «товар.полныйкод»

   megalodon

46 — 04.02.09 — 15:58

как всегда на мисте чем тупее вопрос тем живее обсуждение.

   gr13

47 — 04.02.09 — 15:59

(46) а ты предложи красивое решение

   NcSteel

48 — 04.02.09 — 16:00

(44) о_0 Гуру, не замечал такого !!

(47) получается (44) самое красивое

   megalodon

49 — 04.02.09 — 16:00

а я предлагал в (10) при наличии ряда условий, а без них штатно запросом низя.

   NcSteel

50 — 04.02.09 — 16:01

(49) что ты так упрям, запросом можно!!!

   megalodon

51 — 04.02.09 — 16:02

(50) твое решение в (17) — это не запрос, а несколько запросов — тогда лучше делать кодом без затей.

   НЕА123

52 — 04.02.09 — 16:03

ПолныйКод — это метод.

ИскомыйРодитель =  спр.НайтиПоКоду(Лев(товар.полныйкод(),1,Найти(товар.полныйкод(),»/»)-1))

и что тут неправильного?

   NcSteel

53 — 04.02.09 — 16:04

КАК у элемента справочника быстро найти самого верхнего родителя?

По этому сабжу запросом можно, ты же усложняешь задачу, но и более сложную задачу тоже лучше делать через запрос.

   gr13

54 — 04.02.09 — 16:05

(50) блин! как?

   megalodon

55 — 04.02.09 — 16:05

(53) да не в запросе это получается, а уже в выборке.

   Sadovnikov

56 — 04.02.09 — 16:06

(52) Неправильно то, что, если не стоит галка Контроль уникальности и серии кодов не в пределах всего справочника, то неизвестно, что ты найдешь.

   НЕА123

57 — 04.02.09 — 16:09

(56)если уникальности нет, то да, не катит.

а если не в пределах спр, то так, по полному коду.

ИскомыйРодитель =  спр.НайтиПоКоду(Лев(товар.полныйкод(),1,Найти(товар.полныйкод(),»/»)-1), Истина)

   Sadovnikov

58 — 04.02.09 — 16:10

(57) Вот так уже чуток лучше :)

   Kashemir

59 — 04.02.09 — 16:12

Наиболее практичное решение на данный момент  (17)… увы.

Более «красивое» можно добится в СКД используя связи наборов данных с передачей параметра. Но по факту это лишь имитация циклических запросов с изменением параметра.

   Kashemir

60 — 04.02.09 — 16:13

(59) + Сорь … имел ввиду (18)

   Sadovnikov

61 — 04.02.09 — 16:13

(59) НайтиПоКоду должно быстрее отработать, при перечисленных выше ограничениях.

   gr13

62 — 04.02.09 — 16:14

(59) а как мне узнать в (17) у конкретного элемента родителя верхнего уровня?

   hhhh

63 — 04.02.09 — 16:16

(62) так он там один и будет в выборке

   НЕА123

64 — 04.02.09 — 16:17

автор-то, автор почему молчит.

   Kashemir

65 — 04.02.09 — 16:19

(62) Опечатался. См. (60)

   H A D G E H O G s

66 — 04.02.09 — 16:22

(63) В выборке, а не в запросе..

1С-ина дополнит (17) запрос еще своими запросами..

   gr13

67 — 04.02.09 — 16:23

(65) я уже понял

   Vika64

68 — 04.02.09 — 16:24

(65) вообще-то мне просто надо было найти у элемента, мне известного:
например МояНоменклатура — (это ссылка) самую его верхнюю папочку, например его родитель Папка1 а у папка1 родитель папка2 и т.д. вот мне надо самую верхнюю папку и ответ мне был дан сразу, спасибо gr13…. Правда я надеялась, что можно узнать самого верхнего типа так:
ИскомыйРодитель = МояНоменклатура.СамыйВерхнийРодитель;
но в 1С этого не предусмотрели.

   vde69

69 — 04.02.09 — 16:25

я при решении похожей задачи (правда не со справочниками а с вложенными БП) создал реквизит «ВерхнийУровень»

   Rebelx

70 — 04.02.09 — 16:28

(0)самый быстрый — посчитать для всех групп группу верхнего уровня и похранить на время надобности в каком-нить соответствии. и по родителю элемента всегда получим нужный верхний элемент

   Vika64

71 — 04.02.09 — 16:31

(69) а можно подробнее? какая была задача и как воплотили?

   H A D G E H O G s

72 — 04.02.09 — 16:31

(69) А если папочку, в которой лежит элемент перенести в другого родителя верхнего уровня?

   vde69

73 — 04.02.09 — 16:34

(72) перезаписывать все элементы :( на самом деле зависит от задачи

у меня для БП изменение вержнего родиделя невозможно по определению

   vde69

74 — 04.02.09 — 16:35

(71) а тебе вообще ЗАЧЕМ это надо делать? какая цель? может решение проще есть?

   gr13

75 — 04.02.09 — 16:50

+1

   NcSteel

76 — 04.02.09 — 16:59

(69) Тогда лучше что то вроде «Номенклатурных групп», доп аналитики

  

vde69

77 — 04.02.09 — 17:02

(76) мы не знаем ЗАЧЕМ, вариантов много

мне это надо было для RLS использовать, там в верхнем БП была группа доступа

Найти верхнего родителя

Автор TataRus, 16 ноя 2021, 11:18

0 Пользователей и 1 гость просматривают эту тему.

Добрый день. Подскажите пожалуйста как найти верхнего Родителя для каждого реквизита из ТЧ и собрать их в СЗ? Значения реквизита я собрала в список, проверила на дубли и дальше пока в тупике.
1212.jpg


TataRus, для удобства ответа, пожалуйста вставляйте свой код в виде текста (текста кода, вот тут вверху иконочка есть Код)
а не в виде картинки — как ее править? что бы вам ответ прислать?  :dfbsdfbsdf: 

если помогло нажмите: Спасибо!


TataRus, Например, найти уровень реквизита и в цикле найти родителя первого уровня для него.


LexaK,

СписокЦфо = Новый СписокЗначений;

Для каждого ТекСтр из Объект.ТабЧасть  Цикл
  БитЦфо = ТекСтр.ДоговорыДокумента.бит_ЦФО;                                                                                                       
 Если ЗначениеЗаполнено(БитЦфо) и СписокЦфо.НайтиПоЗначению(БитЦфо) = Неопределено Тогда
 СписокЦфо.Добавить(БитЦфо);                                 
 КонецЕсли;   
КонецЦикла;                         
 Для а = 0 по СписокЦфо.Количество()-1 Цикл

Вроде так


alexandr_ll, я читала про это, но при попытке реализации цикл не срабатывал


TataRus, примерно такой код попробуйте


...
СписокЦфо = Новый СписокЗначений;
СписокРодителей = Новый СписокЗначений;

Для каждого ТекСтр из Объект.ТабЧасть  Цикл
БитЦфо = ТекСтр.ДоговорыДокумента.бит_ЦФО;                                                                                                       
Если ЗначениеЗаполнено(БитЦфо) и СписокЦфо.НайтиПоЗначению(БитЦфо) = Неопределено Тогда
СписокЦфо.Добавить(БитЦфо);                                 
КонецЕсли;   
КонецЦикла;                         

Для каждого лкСтр Из СписокЦфо Цикл

лкРодительЦФО = ПолучитьРодителя(лкСтр.Значение);
Если СписокРодителей.НайтиПоЗначению(лкРодительЦФО) = Неопределено Тогда
СписокРодителей.Добавить(лкРодительЦФО);                                 
КонецЕсли;   

КонецЦикла;
...
КонецЧегоТамУвас;

&НаСервереБезКонтекста
Функция ПолучитьРодителя(лкЦФО)

лкРодитель = лкЦФО;//сама себе родитель, если других нет
Пока ЗначениеЗаполнено(лкРодитель.Родитель) Цикл
лкРодитель = лкРодитель.Родитель;
КонецЦикла;

Возврат лкРодитель;

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

  • 1 пользователь сказал спасибо!

если помогло нажмите: Спасибо!


LexaK, я так не пробовала, вроде работает, можно дальше идти)
Спасибо большое!


Andrey102019

5 / 4 / 1

Регистрация: 21.10.2019

Сообщений: 194

1

Как найти корневую группу элемента справочника?

16.01.2020, 12:15. Показов 16312. Ответов 19

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Каким образом зная или получив элемент справочника Номенклатура получить самого верхнего/корневого родителя/папки этого элемента номенклатуры? Я как то при доработке делал нечто подобное через процедуру, которая перебирает все дерево справочника и идет до самого верха, но наверно это не очень производительно, да и не помню уже где брал пример этого кода. Может быть есть что-то стандартное, или это можно сделать запросом?

Добавлено через 16 минут
вот наверно как-то так можно, но не хотелось бы делать цепочку пакетного запроса, а в цикле запускать запросы, если родитель не пустой, то следующий «шаг»/запрос на верх.

1C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
ВЫБРАТЬ
    Номенклатура.Код КАК Код,
    Номенклатура.Наименование КАК Наименование,
    Номенклатура.Родитель КАК Родитель
ПОМЕСТИТЬ ВТ_Родитель
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Ссылка = &ссылка
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Родитель.Наименование КАК Наименование,
    ВТ_Родитель.Родитель КАК Родитель,
    Номенклатура.Родитель КАК Родитель1
ПОМЕСТИТЬ ВТ_Родитель2
ИЗ
    ВТ_Родитель КАК ВТ_Родитель
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
        ПО ВТ_Родитель.Родитель = Номенклатура.Ссылка
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Родитель2.Наименование КАК Наименование,
    ВТ_Родитель2.Родитель КАК Родитель,
    ВТ_Родитель2.Родитель1 КАК Родитель1,
    Номенклатура.Родитель КАК Родитель2
ИЗ
    ВТ_Родитель2 КАК ВТ_Родитель2
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
        ПО ВТ_Родитель2.Родитель1 = Номенклатура.Ссылка

Добавлено через 15 секунд
вот наверно как-то так можно, но не хотелось бы делать цепочку пакетного запроса, а в цикле запускать запросы, если родитель не пустой, то следующий «шаг»/запрос на верх.

1C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
ВЫБРАТЬ
    Номенклатура.Код КАК Код,
    Номенклатура.Наименование КАК Наименование,
    Номенклатура.Родитель КАК Родитель
ПОМЕСТИТЬ ВТ_Родитель
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Ссылка = &ссылка
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Родитель.Наименование КАК Наименование,
    ВТ_Родитель.Родитель КАК Родитель,
    Номенклатура.Родитель КАК Родитель1
ПОМЕСТИТЬ ВТ_Родитель2
ИЗ
    ВТ_Родитель КАК ВТ_Родитель
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
        ПО ВТ_Родитель.Родитель = Номенклатура.Ссылка
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Родитель2.Наименование КАК Наименование,
    ВТ_Родитель2.Родитель КАК Родитель,
    ВТ_Родитель2.Родитель1 КАК Родитель1,
    Номенклатура.Родитель КАК Родитель2
ИЗ
    ВТ_Родитель2 КАК ВТ_Родитель2
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
        ПО ВТ_Родитель2.Родитель1 = Номенклатура.Ссылка



0



1870 / 1277 / 458

Регистрация: 16.01.2015

Сообщений: 5,583

16.01.2020, 12:16

2

Andrey102019, Один из способов:
Посмотри в СП «ПолныйКод()». Получаешь все коды вышестоящих элементов, выделяешь первый и ищешь по коду в справочнике

Добавлено через 20 секунд
Andrey102019, Один из способов:
Посмотри в СП «ПолныйКод()». Получаешь все коды вышестоящих элементов, выделяешь первый и ищешь по коду в справочнике



0



1183 / 723 / 210

Регистрация: 22.04.2013

Сообщений: 5,325

Записей в блоге: 1

16.01.2020, 12:18

3

Получение всех родителей элемента

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

взято отсюда



0



Andrey102019

5 / 4 / 1

Регистрация: 21.10.2019

Сообщений: 194

16.01.2020, 14:13

 [ТС]

4

Цитата
Сообщение от Yulunga
Посмотреть сообщение

Получение всех родителей элемента

спасибо за труд, но это и так понятно, по логике. Вот написал работающий код, остановлюсь на этом

1C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Процедура КнопкаВыполнитьНажатие(Кнопка)
ТекущийЭлементНоменклатуры=ПоискВерхнегоРодителя(ПолеВвода1);
    
Для ном=1 По 10 Цикл
        
    Если ТекущийЭлементНоменклатуры.Родитель = Справочники.Номенклатура.ПустаяСсылка() Тогда 
        ПолеВвода2=ТекущийЭлементНоменклатуры;
 
        Прервать;
    Иначе
        ТекущийЭлементНоменклатуры=ПоискВерхнегоРодителя(ТекущийЭлементНоменклатуры);
    
       КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры
 
Функция ПоискВерхнегоРодителя(Наименование)
            
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Номенклатура.Наименование КАК Наименование,
        |   Номенклатура.Родитель КАК Родитель
        |ИЗ
        |   Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |   Номенклатура.Ссылка = &ссылка";
    
    Запрос.УстановитьПараметр("ссылка", Наименование);
    
    Результат = Запрос.Выполнить();
    
    Выборка = Результат.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        Возврат  Выборка.Родитель;
    КонецЦикла;
    
    
КонецФункции;

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



0



1183 / 723 / 210

Регистрация: 22.04.2013

Сообщений: 5,325

Записей в блоге: 1

16.01.2020, 15:42

5

в том-то и дело, что по логике было удивительно увидеть на ИТС-е слова родитель.родитель.родитель.родитель.родитель ))))
а так да.



0



5 / 4 / 1

Регистрация: 21.10.2019

Сообщений: 194

16.01.2020, 16:21

 [ТС]

6

Цитата
Сообщение от Yulunga
Посмотреть сообщение

увидеть на ИТС-е слова родитель.родитель.родитель.родитель.родитель

да, я тоже усмехнулся когда такое увидел на ИТСе, хотя некий смысл есть, код короче, но некрасиво. Думаю это следует понимать так — руки у разработчика не дошли, что бы написать такую функцию (хотя не долго бы и написать, в редких случаях функция была бы полезна), взяли и извернулись, пусть коряво, но что-то есть)



0



1870 / 1277 / 458

Регистрация: 16.01.2015

Сообщений: 5,583

16.01.2020, 16:29

7

Andrey102019, А чем не устраивает ПолныйКод()? Самого кода пять-шесть строчек, быстро и точно. Но… хозяин-барин, плодите родитель.родитель.родитель…



1



1183 / 723 / 210

Регистрация: 22.04.2013

Сообщений: 5,325

Записей в блоге: 1

16.01.2020, 16:32

8

polax, а при чём тут Андрей? это ты у итс-ников спрашивай )))
п.с. про полный код не в курсе. завтра надо будет потрогать. спасибо.



0



Xomych

856 / 655 / 111

Регистрация: 01.11.2012

Сообщений: 2,410

16.01.2020, 16:40

9

По опыту самое оптимальное это вот

1C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    З.Текст = "ВЫБРАТЬ
        |   ВЫБОР ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
        |       КОГДА Спр.Родитель.Родитель
        |           ТОГДА Спр.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель.Родитель.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель.Родитель.Родитель.Родитель
        |       ИНАЧЕ ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
        |   КОНЕЦ КАК Марка
        |ИЗ Справочник.Номенклатура КАК Спр
        |ГДЕ Спр.Ссылка = &Ссылка";



1



polax

1870 / 1277 / 458

Регистрация: 16.01.2015

Сообщений: 5,583

16.01.2020, 16:52

10

Yulunga, ИТС-ники — это их проблемы, я же подсказал может и нетривиальный, но рабочий способ.
Берем ссылку номенклатуры и применяем метод Полный код

1C
1
СтрокаКодов = СсылкаНоменклатуры.ПолныйКод();

Получаем строку примерно вида «002/005/009/045», где 045 код самого элемента по ссылке, остальное — коды родителей. Первый в строке «002» и есть код верхнего родителя.
Получить его из строки — минутное дело и

1C
1
ВерхнийРодитель = Справочники.Номенклатура.НайтиПоКоду(НайденныйВехнийКод)

Добавлено через 11 минут
Xomych, А если уровень вложенности, 7, 8, 10?



0



1870 / 1277 / 458

Регистрация: 16.01.2015

Сообщений: 5,583

16.01.2020, 17:02

11

Сделал пример. Создал Номенклатуру ЧтоТам с уровнем вложенности 10. Код элементу 0035, код верхнего каталога 006 (скрин1) Повесил на кнопку формы Расходной код (скрин2) Результат в Нужное — элементарно превращается в нужное значение. И никакаких запросов и кучи родителей

Миниатюры

Как найти корневую группу элемента справочника?
 

Как найти корневую группу элемента справочника?
 



0



Xomych

856 / 655 / 111

Регистрация: 01.11.2012

Сообщений: 2,410

17.01.2020, 09:05

12

Цитата
Сообщение от polax
Посмотреть сообщение

Xomych, А если уровень вложенности, 7, 8, 10?

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

Добавлено через 15 минут
Вот код, на справочнике с 5 уровневой иерархией и количеством карточек больше 500000 отрабатывает меньше секунды.

1C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Функция ПолучитьКоличествоУровней()
    З = Новый Запрос;
    З.Текст = "ВЫБРАТЬ
              | Номенклатура.Ссылка КАК Ссылка
              |ИЗ
              | Справочник.Номенклатура КАК Номенклатура
              |ГДЕ
              | Номенклатура.ЭтоГруппа
              | И НЕ Номенклатура.ПометкаУдаления";
    
    КолУровней = 0;
    Выб = З.Выполнить().Выбрать();
    Пока Выб.Следующий() Цикл
        
        КолУровней = Макс(КолУровней, Выб.Ссылка.Уровень());
        
    КонецЦикла;   
    
    Возврат КолУровней;
КонецФункции    
 
Функция ПолучитьТоварыСМаркой() Экспорт 
    
    //получаем количество уровней в справочнике Номенклатура
    Если Метаданные.Справочники.Номенклатура.ОграничиватьКоличествоУровней Тогда
        КолУровней = Метаданные.Справочники.Номенклатура.КоличествоУровней;
    Иначе
        КолУровней = ПолучитьКоличествоУровней();
    КонецЕсли;
    
    //генерим текст запроса для получения марки в соответствии с количеством уровней в справочнике
    ТекстЗапроса = "ВЫБРАТЬ
                   |    Номенклатура.Ссылка КАК Номенклатура,
                   |    Номенклатура.Код КАК КодНоменклатуры,
                   |ВЫБОР";
    
    СтрТов = "Номенклатура.Родитель";         
    Для i = 1 по КолУровней Цикл
        ТекстЗапроса = ТекстЗапроса + "
                |КОГДА "+СтрТов+".Родитель = ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) ТОГДА "+СтрТов;
        
        СтрТов = СтрТов + ".Родитель";
    КонецЦикла;                      
    
    ТекстЗапроса = ТекстЗапроса + "
                |КОНЕЦ КАК Марка
                |ИЗ
                | Справочник.Номенклатура КАК Номенклатура
                |ГДЕ Номенклатура.Родитель <> ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
                |   И НЕ Номенклатура.ЭтоГруппа 
                |   И НЕ Номенклатура.ПометкаУдаления
                |";
 
    
    З=Новый Запрос;
    З.Текст = ТекстЗапроса;
    
    Возврат З.Выполнить().Выгрузить();
КонецФункции



1



Andrey102019

5 / 4 / 1

Регистрация: 21.10.2019

Сообщений: 194

17.01.2020, 12:03

 [ТС]

13

Цитата
Сообщение от polax
Посмотреть сообщение

А чем не устраивает ПолныйКод()

устраивает) я просто не знал, что есть такая функция

Добавлено через 4 минуты

Цитата
Сообщение от Xomych
Посмотреть сообщение

По опыту самое оптимальное это вот

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

1C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Запрос.УстановитьПараметр("ссылка", Текущая...);
                Результат = Запрос.Выполнить();
                Выборка = Результат.Выбрать();
                Пока Выборка.Следующий() Цикл
                    Если Выборка.Родитель2=Неопределено Тогда
                        Родитель...=Выборка.Родитель;
                    ИначеЕсли
                        Родитель...=Выборка.Родитель1;
                    ИначеЕсли
                        Родитель...=Выборка.Родитель2;
                    Иначе
                        Родитель...=Выборка.Родитель3;
                    КонецЕсли;
                КонецЦикла;
            КонецЕсли;

Добавлено через 6 минут

Цитата
Сообщение от polax
Посмотреть сообщение

ПолныйКод()

А есть еще малознакомые функции типа этой? Которые были бы полезны в некоторых случаях, но их мало кто знает? (или тут чисто индивидуально или просто пройтись по СП и пооткывать все непонятное/незнакомое)

Добавлено через 18 минут
Спасибо всем за помощь, код существенно сократился

1C
1
Если Найти(ПолныйКод(Выборка.Т....),"00001") Тогда

это конечно частный случай, но это мой частный случай)

Добавлено через 7 минут
нет немного не так

1C
1
Если Найти(Выборка.Т.....ПолныйКод(),"00001") Тогда



0



blade_snl

4 / 4 / 1

Регистрация: 02.02.2017

Сообщений: 180

17.06.2021, 15:09

14

Цитата
Сообщение от Xomych
Посмотреть сообщение

По опыту самое оптимальное это вот

1C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    З.Текст = "ВЫБРАТЬ
        |   ВЫБОР ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
        |       КОГДА Спр.Родитель.Родитель
        |           ТОГДА Спр.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель.Родитель.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель.Родитель.Родитель.Родитель
        |       ИНАЧЕ ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
        |   КОНЕЦ КАК Марка
        |ИЗ Справочник.Номенклатура КАК Спр
        |ГДЕ Спр.Ссылка = &Ссылка";

отличная штука! благодарен.
но подскажите, умные люди, можно ли это все включить в Запрос к Справочнику Номенклатура, чтоб это поле «Марка» отобразило мне значения по всем строкам Результата? Голову уже поломал, никак не могу придумать конструкцию запроса…

имею ввиду такой запрос:

1C
1
2
3
4
5
ВЫБРАТЬ
 Спр.Код,
 Спр.Наименование,
 ... (сюда включить ХХХ.Марка из вышеизложенного запроса)
ИЗ Справочник.Номенклатура КАК Спр

а в итоге получить таблицу с полями:

Код | Наименование | Марка ….



0



Yulunga

1183 / 723 / 210

Регистрация: 22.04.2013

Сообщений: 5,325

Записей в блоге: 1

17.06.2021, 16:37

15

1C
1
2
3
4
5
6
выбор когда а=б тогда "вася"
когда а=в тогда "петя"
когда а=Ъ тогда "деревня зюзюкино"
иначе "пятая точка"
конец
как марка,



1



blade_snl

4 / 4 / 1

Регистрация: 02.02.2017

Сообщений: 180

17.06.2021, 17:14

16

Цитата
Сообщение от Yulunga
Посмотреть сообщение

1C
1
2
3
4
5
6
выбор когда а=б тогда "вася"
когда а=в тогда "петя"
когда а=Ъ тогда "деревня зюзюкино"
иначе "пятая точка"
конец
как марка,

))) действительно, так стало нагляднее, сразу разобрался, спасибо огромное!



0



264 / 219 / 95

Регистрация: 07.04.2011

Сообщений: 1,358

18.06.2021, 16:17

17

Текст Запроса….
Где Номенклатура.Родитель Есть Null

Вернёт самый верхний каталог



1



4 / 4 / 1

Регистрация: 02.02.2017

Сообщений: 180

18.06.2021, 16:29

18

Цитата
Сообщение от OverDozero
Посмотреть сообщение

Текст Запроса….
Где Номенклатура.Родитель Есть Null

Вернёт самый верхний каталог

но через ГДЕ — оно же просеет записи…
а моя задача — вывести ВСЕ записи, чтоб одним из столбцов выводилось имя корневого каталога по каждой номенклатурине…



0



Xomych

856 / 655 / 111

Регистрация: 01.11.2012

Сообщений: 2,410

19.06.2021, 08:19

19

blade_snl,

1C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
З.Текст = "ВЫБРАТЬ
        |Спр.Код,
        |Спр.Наименование,
        |   ВЫБОР ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
        |       КОГДА Спр.Родитель.Родитель
        |           ТОГДА Спр.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель.Родитель.Родитель
        |       КОГДА Спр.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель
        |           ТОГДА Спр.Родитель.Родитель.Родитель.Родитель.Родитель
        |       ИНАЧЕ ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
        |   КОНЕЦ КАК Марка
        |ИЗ Справочник.Номенклатура КАК Спр



2



blade_snl

4 / 4 / 1

Регистрация: 02.02.2017

Сообщений: 180

19.06.2021, 11:03

20

Цитата
Сообщение от Xomych
Посмотреть сообщение

blade_snl,

1C
1
З.Текст = "ВЫБРАТЬ

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

1C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ВЫБРАТЬ 
    ВЫБОР ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
       КОГДА Номенклатура.Родитель.Родитель
           ТОГДА Номенклатура.Родитель
       КОГДА Номенклатура.Родитель.Родитель.Родитель
           ТОГДА Номенклатура.Родитель.Родитель
       КОГДА Номенклатура.Родитель.Родитель.Родитель.Родитель
           ТОГДА Номенклатура.Родитель.Родитель.Родитель
       КОГДА Номенклатура.Родитель.Родитель.Родитель.Родитель.Родитель
           ТОГДА Номенклатура.Родитель.Родитель.Родитель.Родитель
       КОГДА Номенклатура.Родитель.Родитель.Родитель.Родитель.Родитель.Родитель
           ТОГДА Номенклатура.Родитель.Родитель.Родитель.Родитель.Родитель
       ИНАЧЕ ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
    КОНЕЦ КАК КорнКаталогНаименование,
 
    Номенклатура.ЭтоГруппа,
    Номенклатура.Код,
    Номенклатура.Наименование
ИЗ
    Справочник.Номенклатура КАК Номенклатура



0



В продолжение публикации «Транзитивное замыкание запросом» [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. Определение множества взаимозаменяемых позиций (аналогов) номенклатуры.

Существует несколько решений для хранения информации о взаимозаменяемости номенклатурных позиций [//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 записей регистра сведений «Аналоги номенклатуры» для этих связей.

Аналоги в УПП

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

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

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

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

Понравилась статья? Поделить с друзьями:

Не пропустите также:

  • Как найти человека который в другой стране
  • Как составить исковое заявление если нет договора аренды
  • Как найти подработку на один день
  • Как исправить течь в туалете
  • Как найти девушку которую видел на улице

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии