Имя: Пароль:
1C
1С v8
Таблица иерархии и проверка зацикленности
0 Ненавижу 1С
 
гуру
27.07.11
15:09
1. Нет 100% (7)
2. Да 0% (0)
Всего мнений: 7

Есть таблица с двумя полями: ссылка и родитель. Ссылка в таблице уникальна и всегда заполнена. Родитель - это ссылка непосредственного родителя (он тоже обязательно есть в некоторой записи этой таблицы в поле Ссылка). Если родителя нет, то поля Родитель не заполнено (ммм... в терминах 1С "пустая ссылка") - это корневой элемент.
Требуется написать ОДИН запрос (можно пакетный) на языке запросов 1С, с помощью которого можно проверить нет ли в этой таблице иерархии зацикленности? То есть проверить на валидность данные.

Взлетит?
1 Ник второй
 
27.07.11
15:11
Давай свой вариант. Как можно судить о взлетах ?
2 Ненавижу 1С
 
гуру
27.07.11
15:12
(1) нужен запрос, если он есть, то взлетит, если есть хоть какое-то приемлимое обоснование, что нельзя - значит не взлетит
3 Fragster
 
гуру
27.07.11
15:13
это порочная структура, реально. правильная структура - ссылка, левое значение, правое значение, уровень. родитель опционален.

и дерево вида

(1,6,0)
(2,3,1)(4,5,1)
4 Ненавижу 1С
 
гуру
27.07.11
15:14
(3) структура уже задана, порочная она или нет, другой вопрос

меня интересует можно проверить запросом на зацикленность или нет
5 Ник второй
 
27.07.11
15:16
Имхо. нет.
6 Jstunner
 
27.07.11
15:16
невозможно утверждать о зацикленности не пройдя все точки. Циклов в запросах нет

Нет
7 Ник второй
 
27.07.11
15:16
голос забыл

Нет
8 Fragster
 
гуру
27.07.11
15:17
(4) может коррелированными подзапросами и можно как-то извратится. только это не стандартный T_SQL, да и хз, только 1 раз написал такой запрос, как раз для построения дерева (но там гарантированно не было циклов)
9 Fragster
 
гуру
27.07.11
15:17
ыц

Нет
10 Ник второй
 
27.07.11
15:17
(6) Циклы в запросах есть , но не те.
11 Axel2009
 
27.07.11
15:31
(0) нужно выдать на экран или обработать результат?
12 catena
 
27.07.11
15:42
КОличество уровней неизвестно?
13 Lama12
 
27.07.11
15:44
Недавно тема обсасывалась, но без запросов.
Та дано оптимальное решение. Если на запрос переведешь, то получится.
14 Ненавижу 1С
 
гуру
27.07.11
15:51
(11) нужно запросом дать данные, которые уже обработки не требуют (или требуют за фиксированное время)
15 Mort
 
27.07.11
15:52
И это можно доказать, оперируя порядком вычислений необходимого для решения данной задачи и порядком который может "предложить" один запрос.
16 Mort
 
27.07.11
15:53
+(15) Почему то не проголосовалось.

Нет
17 Юрий Лазаренко
 
27.07.11
15:54
(0) Сам недавно бодался с подобной ботвой, в итоге остановился на рекурсии.

Нет
18 Axel2009
 
27.07.11
15:57
(14) если тока вывести, можно скд попробовать, там есть рекурсии встроенные.. набор данных сам на себя зациклить..
19 sikuda
 
27.07.11
16:23
Реляционный подход требует получения данных за ограниченное количество внутренних запросов в системе. Если вы используете рекурсию типа TSQL оператор with, то количесто подзапросов растет как квардат от уровня вложенности. Если количество вложенности до 10, то этот костыль подходит. Но запихнуть его в 1С мне не удалось.
В общем случае создавайте кэш-РегистрСведений Родитель(любого уровня), Ссылка, УровеньВложенности. Записывайте его при любом изменении иерархии. С помощью этой структуры ваш запрос строиться легко.

Нет
20 Ахиллес
 
27.07.11
16:35
Что есть в данном случае "Зацикленность"? У Ссылки1 родитель равен Сылка2, а у Ссылка2 родитель равен Ссылка1?
21 Axel2009
 
27.07.11
16:38
(20) это была бы халява
22 Ахиллес
 
27.07.11
16:40
(21) Что тогда найти надо? Неоднократные ссылки? Ещё большая халява тогда. Что есть зацикленность?
23 Axel2009
 
27.07.11
16:41
(22)
ссылка1, ссылка2
ссылка2, ссылка3,
...
ссылкаN, ссылка1
24 Ахиллес
 
27.07.11
16:45
Запрос1: Выбрать Элемент, Родитель, группировка по Элемент,Родитель, где Родитель не пустое значение.
Запрос2: Выбрать Элемент2, Родитель2, группировка по Элемент2,Родитель2, где Родитель2 не пустое значение.
Внутреннее соединение по Элемент = Родитель2
З.Ы. Если х.ню сморозил - звиняйте :-)
25 Ахиллес
 
27.07.11
16:59
Не это ересь я какую то написал. Необходимо ещё уровень элемента знать. И дополнительное условие по сравнению уровней, я так понимаю.
26 Fragster
 
гуру
27.07.11
17:01
(25) а какой уровень у зациклившихся элементов?
27 Ахиллес
 
27.07.11
17:05
(26) У родителя меньше чем у элемента?
28 Ахиллес
 
27.07.11
17:08
то есть больше. :-)
29 Fragster
 
гуру
27.07.11
17:26
(27) а кто из них родитель? там же как раз и прикол в неоднозначности уровня
30 Ахиллес
 
27.07.11
17:51
(29) Цитата из (0) Есть таблица с двумя полями: ссылка и родитель.  Значит надо просто дополнить эту таблицу уровнем элемента и уровнем родителя
31 Axel2009
 
27.07.11
17:52
(30) а что это даст?
32 Ахиллес
 
27.07.11
17:54
(31)Если уровень родителя больше уровня элемента, то косяк.
Собственно при нормальном заполнении ситуация в (23) невозможна в принципе. Х.З. Как эту таблицу Ненавижу 1С заполняет и почему у него там какая то зацикленность образовалась.
33 Axel2009
 
27.07.11
17:56
(32) когда дерево заполняет пользователь на глаз, то каждый пересчет может занимать "долгое" время наверна
34 Ахиллес
 
27.07.11
18:01
(33) Нифига не понял.
35 Axel2009
 
27.07.11
18:02
ну вот сидит пользователь, дается ему 2 колонки, ссылка, родитель. он заполняет ее сначала, а потом надо проверить, все ли он корректно ввел. если по каждому тыку проверять, пользователь будет сидеть по паре секунд и ждать когда же это произойдет..
36 Живой Ископаемый
 
27.07.11
18:04
2(35) зачем проверять после того как он наделал ошибок а не каждый раз как он вводит новую строку?
Или это специальный пользователь, обученный заполнять сначала только одну колонку, а потом только вторую во всей таблице сразу?
37 Живой Ископаемый
 
27.07.11
18:05
"если по каждому тыку проверять" непонятно пчоему по паре секунд а не мгновенно
38 Fragster
 
гуру
27.07.11
18:06
(30) у первого элемента родителем второй, у второго - первый. у кого какой уровень?
39 Ахиллес
 
27.07.11
18:06
(35)  В момент заполнения элемента и родителя пусть проверяются уровни элемента и уровень родителя. Если уровень родителя больше уровня эдемента, включается разрядник в сиденье стула на 1000 вольт. Я не могу придумать, как иначе образуется эта зацикленность?
40 Ахиллес
 
27.07.11
18:08
(38) Мы ведь о многоуровневом справочнике говорим? В таком случае Уровень это объективное свойство элемента. Не надо думать какой уровень, надо просто взять и посмотреть на него.
41 Fragster
 
гуру
27.07.11
18:09
(40) в (0) нет уровня, есть таблица с 2 колонками. требуется проверить возможность построения дерева.
42 Живой Ископаемый
 
27.07.11
18:10
2(40) нет, не обязательно... Автор может думать как организовать альтернативную иерархию... Ну например...
Есть справочник контрагентов - он заполняется как бог на душу положит бухгалтерии или например по Гегорафическому принципу... А на другом уровне эти контрагенты связаны между собой иерархией Агент-субагент
43 Ахиллес
 
27.07.11
18:10
(41) В таблице есть ССЫЛКИ, а у ссылки есть метод Уровень()
44 Живой Ископаемый
 
27.07.11
18:12
по географическому принципу
1.ЦАО
1.1.МосковскаяОбласть
1.1.1 агент Вася
1.2. Калужская Область
1.2.1 агент Петя

а альтернативная ирерхия выглядит так:
1. агент Вася из московской области
1.1. субагент Петя из Калужской области
45 Fragster
 
гуру
27.07.11
18:13
(43) при чем тут? допустим, мы строим произвольную (альтернативную) иерархию, и у нас РС с 2 измерениями: Ссылка и Родитель.
46 Ахиллес
 
27.07.11
18:16
(44) Нарисуй зацикленное дерево к первой иерархии.
47 Fragster
 
гуру
27.07.11
18:17
*facepalm*
48 Живой Ископаемый
 
27.07.11
18:18
2(46) а ему и не нужно проверять зацикленность первой. Он хочет проверить зацикленность второй.
а выглядит это просто:
Агент:                            СуперАгент
1. агент Вася из московской области | 1.1. субагент Петя из Калужской области
1.1. субагент Петя из Калужской области | 1. агент Вася из московской области
49 МихаилМ
 
27.07.11
18:22
--------------------------
можно
только если известно макс колво вложенности уровней


но можно построить более эффективнуюю иерархию :
в cсылке можно закодировать иерархию.
и проверять её при создании элемента.

тогда можно создать эффективный индекс.

Нет
50 rs_trade
 
27.07.11
18:24
(19)  почему только до 10?
51 Ахиллес
 
27.07.11
18:33
Если таблица соответствует новой иерархии, то действует простое правило, кто первый встал, того и тапки. Мы же должны знать на какой уровень иерархии мы хотим поместить создаваемый элемент? Как только создаётся элемент в новой иерархии ему моментально присваивается уровень. Без этого условия новую иерархию вообще невозможно построить. А раз уж мы присвоили уровень, то мы можем сравнивать их для новой пары.
52 Ахиллес
 
27.07.11
18:43
Для случая (48)
Создаем 1. агент Вася из московской области и решаем, что он будет родителем всех агентов. (Должны же мы с чего то начать дерево? Поэтому получите Вася первый уровень и распишитесь)
Далее мы создаём 1.1. субагент Петя из Калужской области и решаем, что вася должен стать его родителем. Да не вопрос. Вот тебе Петя второй уровень.
Дальше мы вышли покурить, а кто то нам решил помочь.
Заводит 1.1. субагент Петя из Калужской области и решает, что Петя должен стать родителем Васи. И тут же получает граблями по лбу, потому, что Вася уже был заведён ранее и уже имеет уровень 1 который меньше чем у предпологаемого родителя.
53 Живой Ископаемый
 
27.07.11
18:45
2(52) все верно, как-то так...
54 vmv
 
27.07.11
18:50
уже давно создан алгоритм превращения тз в дерево по набору полей иерархии посредством запсроса с менеджером временных таблиц(ищем на инфостаре).

его, кто хотел, докрутил по корректной обработке всех полей таблицы. Заодно он покакзывает зацикленности или его(алгоритм) можно заставить это делать

веласипед снова изобретаем
55 МихаилМ
 
27.07.11
18:51
(54)
пожалуста ссылку дайте.
56 Ахиллес
 
27.07.11
18:53
(54) На какой фабрике таких умных делают? Или алгоритм опиши или ссылку прямую дай. А на предъявы типа ищите на инфостарте/гугле/яндексе можно аналогичный посыл получить, куда Макар телят не гонял.
57 vmv
 
27.07.11
18:53
(52) "вольная" работа с группами - однин из больших минусов платформы 1С. Мне пришлось к ключевым справочникам: ОС, Контрагенты, Номенкратура, ФизЛица прикручивать подписчики ПередЗаписью, которые при создании пользователем нового элемента "кладут" его программно именно в тут группу, которая определена
58 Ахиллес
 
27.07.11
18:55
(57) Ты не зациклишь справочник в 1С.
59 Живой Ископаемый
 
27.07.11
18:58
2(58) даже если будет включена не иерархия групп, а иерархия групп и элементов? даже если после интерактивной записи потом программно для элемента-родителя назначу родителем элемент-потомок?
не проверял, просто спрашиваю.
60 vmv
 
27.07.11
19:00
(58) не-а, В новом ПланВидов характеристик задаются правила иерархии для этих справочников согласно наборам реквизитов объекта.

Например если при вводе нового контрагента выбрали, что  это юр.лицо, что форма собственности "ООО" и это, допустим поставшик, то он "падает" в свою иерархию  и любая попытка перемешщения его из групы будет "натыкаться" на это правило расположения в иерахии, упорно записывая его в ту группу, что определена ПВХ.

Если пользователь ничего не выбрал, то элемент падает в корень, а пользователь получает втык за лень и скопление незаполненных элементов.
61 Ахиллес
 
27.07.11
19:01
(59) Ну интерактивно точно не получится. Я верю в то, что создатели 1С не конченые дауны, а програмно тоже не пробовал. Завтра попробую.
62 Живой Ископаемый
 
27.07.11
19:02
2(60) да, тоже способ.
63 vmv
 
27.07.11
19:12
(56) пример вызова и метод ниже, метод не совсем оптимален в смысле кода, но я ему "скармливаю" любые тз для получения иерархий и итогов по числовым полям, полезно, например, для работы с банками, группировать дата/банк/Валюта деревья и импортить потом куда хочь


// Инициализация массива колонок группировок и структуры с колонками пересчета.
   // В структуру колонок пересчета включаем все поля, но суммирование будет произведено только по числовым.
   мКолонкиГруппировок = Новый Массив;
   мКолонкиГруппировок.Добавить("Уровень");
   СтруктураКолонокПересчета = Новый Структура;
   Для Каждого Колонка Из ТзСоставКлассификации.Колонки Цикл
       КолонкиИмя = Колонка.Имя;
       Если ЗначениеЗаполнено(мКолонкиГруппировок.Найти(КолонкиИмя)) ИЛИ КолонкиИмя = "НомерСтроки" Тогда
           Продолжить;
       КонецЕсли;
       СтруктураКолонокПересчета.Вставить(КолонкиИмя, "Сумма");
   КонецЦикла;
   
   // Получение из таблицы значений дерева значений через метод менеджера внешних таблиц.
   ДеревоСоставаПорядкаИерархии = AddДеревья.ПолучитьДеревоПоТаблице(ТзСоставКлассификации, мКолонкиГруппировок, СтруктураКолонокПересчета, Истина, "Элементы");


// Функция получает дерево значений по таблице значений, достраивая иерархию
//
//  Параметры:
//   1.Источник                  - "ТаблицаЗначений"
//   2.мКолонкиГруппировок       - массив имен колонок по которой должна быть достроена несуществующая иерархия
//   3.СтруктураКолонокПересчета - Структура - Структура с именами колонок требующих пересчета и функциями пересчета
//
Функция ПолучитьДеревоПоТаблице(Источник, мКолонкиГруппировок, СтруктураКолонокПересчета, СИерархией=Истина, ТипИзмеренияЗапроса="ИЕРАРХИЯ") Экспорт
   Перем мКолонкиВыборки;
   
   Если мКолонкиГруппировок.Количество() = 0 Тогда
       Возврат Новый ДеревоЗначений;
   КонецЕсли;
   
   мКолонкиВыборки = ОбщегоНазначения.СкопироватьУниверсальнуюКоллекцию(мКолонкиГруппировок);
   Для Каждого КолонкаПересчета Из СтруктураКолонокПересчета Цикл
       Если мКолонкиВыборки.Найти(КолонкаПересчета.Ключ) = Неопределено Тогда
          мКолонкиВыборки.Добавить(КолонкаПересчета.Ключ);
       КонецЕсли;
   КонецЦикла;
   //Если мКолонкиВыборки.Найти("НомерСтроки") = Неопределено Тогда
   //    мКолонкиВыборки.Вставить(0, "НомерСтроки");
   //КонецЕсли;
   
   // Получаем временную таблицу
   Запрос = Новый Запрос;
   МВТ    = Новый МенеджерВременныхТаблиц;
   Запрос.МенеджерВременныхТаблиц = МВТ;
   
   ЗапросТекст = "ВЫБРАТЬ ";
   
   СЧ = 0;
   Для Каждого КолонкаИмя Из мКолонкиВыборки Цикл
       СЧ = СЧ + 1;
       ЗапросТекст = ЗапросТекст + Символы.ПС + "ТЗСостав."+ КолонкаИмя + " КАК "+ КолонкаИмя + ?(СЧ = мКолонкиВыборки.Количество(),"",",");
   КонецЦикла;
   
   ЗапросТекст = ЗапросТекст + Символы.ПС + "ПОМЕСТИТЬ ТЗВременная
   |ИЗ
   |    &ТЗСостав КАК ТЗСостав";
   
   Запрос.Текст = ЗапросТекст;
   Запрос.УстановитьПараметр("ТЗСостав", Источник);
   Запрос.Выполнить();
   
   // Получаем Дерево запросом из временной таблицы
   Запрос = Новый Запрос;
   Запрос.МенеджерВременныхТаблиц = МВТ;
   ЗапросТекст = "ВЫБРАТЬ ";
   СЧ = 0;
   Для Каждого КолонкаИмя Из мКолонкиВыборки Цикл
       СЧ = СЧ + 1;
       ЗапросТекст = ЗапросТекст + Символы.ПС + "ТЗСостав."+ КолонкаИмя + " КАК "+ КолонкаИмя + ?(СЧ =  мКолонкиВыборки.Количество(),"",",");
   КонецЦикла;
   ЗапросТекст = ЗапросТекст + Символы.ПС + " ИЗ
   |    ТЗВременная КАК ТЗСостав
   |ИТОГИ";
   
   //
   СчЧисловыхПолей = 0;
   Для Каждого КолонкаПересчета Из СтруктураКолонокПересчета Цикл
       ТипКлюча = Источник.Колонки[КолонкаПересчета.Ключ].ТипЗначения;
       ПустоеЗначение = ТипКлюча.ПривестиЗначение();
       Если ТипЗнч(ПустоеЗначение) = Тип("Число") Тогда
           СчЧисловыхПолей = СчЧисловыхПолей + 1;
       КонецЕсли;
   КонецЦикла;
   
   //
   СЧ = 0;
   Для Каждого КолонкаПересчета Из СтруктураКолонокПересчета Цикл
       ТипКлюча = Источник.Колонки[КолонкаПересчета.Ключ].ТипЗначения;
       ПустоеЗначение = ТипКлюча.ПривестиЗначение();
       Если ТипЗнч(ПустоеЗначение) <> Тип("Число") Тогда
           Продолжить;
       КонецЕсли;
       СЧ = СЧ + 1;
       ЗапросТекст = ЗапросТекст + Символы.ПС + КолонкаПересчета.Значение + " ("+ КолонкаПересчета.Ключ + ")" + ?(СЧ = СчЧисловыхПолей,"",",");    
   КонецЦикла;
   
   СтрокаИтогиПо = "";
   Для Каждого КолонкаИмя Из мКолонкиГруппировок Цикл
      СтрокаИтогиПо = ?(ПустаяСтрока(СтрокаИтогиПо), КолонкаИмя + " " + ТипИзмеренияЗапроса,  СтрокаИтогиПо + ", " + КолонкаИмя + " " + ТипИзмеренияЗапроса);
   КонецЦикла;
   
   Если Не ПустаяСтрока(СтрокаИтогиПо) Тогда
       ЗапросТекст = ЗапросТекст + Символы.ПС + "ПО
       |    " + СтрокаИтогиПо;
     КонецЕсли;
   
   Запрос.Текст = ЗапросТекст;
   Если СИерархией Тогда
      Дерево = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
   Иначе    
      Дерево = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
   КонецЕсли;
   
   МВТ.Закрыть();
   
   Возврат Дерево;
   
КонецФункции
64 Живой Ископаемый
 
28.07.11
08:39
2(58) Ну... интерактивно да - не выходит:
http://screencast.com/t/a73wZNvDsb6C
65 Живой Ископаемый
 
28.07.11
08:51
Но вот такой запрос:
ВЫБРАТЬ
   2 * 2 КАК Поле1,
   Подразделения.Ссылка,
   Подразделения1.Ссылка КАК Ссылка1
ИЗ
   Справочник.Подразделения КАК Подразделения,
   Справочник.Подразделения КАК Подразделения1
ГДЕ
   Подразделения.Ссылка = &Ссылка
   И Подразделения1.Ссылка = &Ссылка1
Где параметр Ссылка я задаю в элемент первого уровня, а Ссылка1 в его потомка третьего уровня, дает мне одну строку.
к этой строке я применяю такой код:
Первое = СтрокаРезультата.ССылка.ПолучитьОбъект();
Первое.ОбменДанными.Загрузка = Истина;
Первое.Родитель = СтрокаРезультата.ССылка1;
Первое.Записать();

прокатывает, и после этого если открыть форму списка справочника Подразделения - там нет ни элемента первого уровня и ни одного его потомка... Но если выполнить запрос к справочнику вцелом, то эти элементы видны.
И можно даже открыть сам элемент.. Но вот по кнопке "Перейти в список" Толстый клиент подвисает - видимо зацикливается... :))
66 Живой Ископаемый
 
28.07.11
10:59
автор потерял интерес? :)
67 Ненавижу 1С
 
гуру
28.07.11
11:00
(66) автор понял, что задача неразрешима в постановке (0)
автор ошибался когда постил
68 Живой Ископаемый
 
28.07.11
11:03
(67) ну тебя хоть фокус из (65) порадовал? :)
2 + 2 = 3.9999999999999999999999999999999...