AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 05.11.2019, 10:05   #1  
SuperStar88 is offline
SuperStar88
Участник
 
82 / 10 (1) +
Регистрация: 11.08.2017
? AX 2009. Дерево, получить всех предков
Есть узел, надо получить список всех узлов, куда он входит.

Есть запрос, который получает родителей по таблицам BOM и BOMTable.
PS: bomTable.ItemId_X - это код номенклатуры спецификации
X++:
while select itemId_X from bomTable
     join bom where bom.BOMId == bomTable.BOMId && 
            bom.ItemId != bomTable.ItemId_X && bom.ItemId == '01.02.08.01.01.0002'
{
   tmpItemLocal.clear();
   tmpItemLocal.ItemId  = bomTable.ItemId_X;
   tmpItemLocal.LineNum = level+1;
   tmpItemLocal.insert();
}
Как рекурсивно пройтись?

PS: в SQL это будет как-то так:
PHP код:
DECLARE @tbl TABLE (itemid NVARCHAR(33), num INT);
DECLARE @
itemId VARCHAR(MAX);
DECLARE @
kol INT, @num INT;

SET @kol 1SET @num 0;
SET @itemId '01.02.08.01.01.0002'

INSERT INTO @tbl(itemidnum)
SELECT @itemId'', @num AS num;

WHILE @
kol 0
BEGIN
    
---Ищем всех родителей
    INSERT INTO 
@tbl
    SELECT bomtable
.itemid_ztr, @num AS num
    FROM BOMTable bomtable
        JOIN BOM bom ON bom
.dataareaid bomtable.dataareaid
                        
AND bom.bomid bomtable.bomid
                        
AND bomtable.itemid_ztr <> bom.itemid
    WHERE bom
.itemid IN SELECT itemid FROM @tbl WHERE num = @num )
          AND 
bomtable.dataareaid 'xxx';

    
SELECT @kol = ( SELECT COUNT(*) FROM @tbl WHERE num = @num );

    
SELECT @num = @num 1;
END;-- WHILE

SELECT FROM @tbl ORDER BY numitemid
Старый 05.11.2019, 10:34   #2  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от SuperStar88 Посмотреть сообщение
Как рекурсивно пройтись?

PS: в SQL это будет как-то так:
один сложный запрос не всегда дает наилучшую производительность в многопользовательской системе.
даже в чистом SQL.

общая рекомендация для SQL - сводите сложный запрос к нескольким простым, для которых с большой вероятностью есть уже скомпилированные планы в кэше и для которых у SQL есть хорошие эвристики.

дополнительная рекомендация для Аксапты - обязательно смотрите на свойство CacheLookup таблицы.

в 2009 для таблиц BOM, BOMTable свойство CacheLookup=Found
это значит, что простые запросы по этим таблицам возможно вообще не будут отправляться на SQL, аксапта будет возвращать уже найденные записи из кэша.

(простые - это запросы по одной таблице, в условиях присутствуют только одно ключевое поле. Как правило, метод find содержит именно такой простой запрос)

поэтому вполне возможно, что стоит свести к X++ методу, который оперирует только простыми запросами по таблицам BOM, BOMTable. Тогда в многопользовательской системе, где много разных пользователей работает с BOM, вы с бОльшей вероятностью получите более быстрый код.

Главное:
* НЕ гонитесь за производительностью ОДНОГО запроса, который выполняется в МОНОПОЛЬНОМ режиме.
* постарайтесь поднимать ОБЩУЮ производительность многопользовательской системы
__________________
полезное на axForum, github, vk, coub.
За это сообщение автора поблагодарили: SuperStar88 (1).
Старый 05.11.2019, 11:16   #3  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,699 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Ну, я так понимаю, вопрос ставится так: В каких спецификациях используется указанная номенклатура, с учетом того, что спецификация сама может выступать как номенклатура для других спецификаций

X++:
    void setLevel(ItemId _itemId, int _level)
    {
        BomTable    bomTable;
        Bom         bom;
        ;
 
        while select itemId_X from bomTable
             join bom where bom.BOMId == bomTable.BOMId &&
                    bom.ItemId != bomTable.ItemId_X && bom.ItemId == _itemId
        {
           tmpItemLocal.clear();
           tmpItemLocal.ItemId  = bomTable.ItemId_X;
           tmpItemLocal.LineNum = _level;
           tmpItemLocal.insert();

           // рекурсия
           setLevel(bomTable.ItemId_X, _level+1);
        }
    }
    ;

    // Вход в рекурсию    
    setLevel('01.02.08.01.01.0002', 1);
Правда, тут не учтена вероятность "зацикливания". Впрочем, и Ваш запрос SQL, тоже это не учитывает.

Если "зацикливание" возможно, то нужно еще дополнительное поле для записи BomId и дополнительный запрос по tmpItemLocal на предмет существования комбинации BomId+ItemId+LineNum и если такая комбинация есть, то не делать запись и не входить в следующий шаг рекурсии

Ну, или просто ограничится глубиной вложенности, скажем, на 10 уровней. Если получилось, что _level больше 10, то это зацикливание и глубже идти не надо.

В принципе, можно сделать и цикл по аналогии с SQL. Вполне можно в запрос включить временную таблицу. Но! В Axapta объединение постоянных и временных таблиц в одном запросе зачастую очень плохо кончается. Как минимум, с точки зрения производительности. А в данном случае еще и с пониманием логики выполнения будут проблемы
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
За это сообщение автора поблагодарили: mazzy (2), SuperStar88 (1).
Старый 05.11.2019, 11:24   #4  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Ну, или просто ограничится глубиной вложенности, скажем, на 10 уровней. Если получилось, что _level больше 10, то это зацикливание и глубже идти не надо.
добавлю только что в аксапте уже есть параметр "Макс. уровень спецификации"
Изображения
 
__________________
полезное на axForum, github, vk, coub.
Старый 05.11.2019, 13:21   #5  
SuperStar88 is offline
SuperStar88
Участник
 
82 / 10 (1) +
Регистрация: 11.08.2017
Благодарю, то что надо!
Вот это bom.ItemId != bomTable.ItemId_X должно предотвращать зацикливание, то есть спецификация не может входить сама в себя
Старый 05.11.2019, 13:31   #6  
AlGol is offline
AlGol
Участник
 
277 / 93 (4) ++++
Регистрация: 24.12.2001
Адрес: Тверь.
Как вариант, рассмотрите возможность сохранения данных о всех родителях ноды в отдельной таблице.
Т.е. выполнять итерационный пробег или запрос по ветке не в момент когда нужен список всех родителей, а при изменении структуры дерева.
Это будет оправдано, если редактирование узлов выполняется реже чем запросы на получение списка родителей.
__________________
Ален ноби, ностра алис.
Что означает - если один человек построил, другой завсегда разобрать может.
Старый 05.11.2019, 13:48   #7  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,164 / 1293 (48) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
Цитата:
Сообщение от SuperStar88 Посмотреть сообщение
Вот это bom.ItemId != bomTable.ItemId_X должно предотвращать зацикливание, то есть спецификация не может входить сама в себя
Только в самом простом случае - когда вхождение непосредственное. Но оно может быть и на других уровнях в многоуровневой спецификации (то есть, на глубине гораздо большей, чем непосредственное вхождение).
Кроме того, просто ItemId проверять не совсем корректно - вполне может быть ситуация, когда номенклатура одна, а конфигурации разные (из одной номенклатуры изготавливаем её подобие, но немного отличающееся) тогда это не зацикливание.
Если учесть конфигурационные группы, периоды действия строки спецификации, тип строки спецификации (например, фантомная может разворачиваться) и другие тонкости, то напрямую по таблице пробегать может быть не очень хорошей идеей. В стандартной Аксе есть классы BomSearch* и BOMHierarchy* там можно подсмотреть примеры.
За это сообщение автора поблагодарили: mazzy (5).
Старый 06.11.2019, 10:37   #8  
SuperStar88 is offline
SuperStar88
Участник
 
82 / 10 (1) +
Регистрация: 11.08.2017
Цитата:
Сообщение от Raven Melancholic Посмотреть сообщение
Только в самом простом случае - когда вхождение непосредственное. Но оно может быть и на других уровнях в многоуровневой спецификации (то есть, на глубине гораздо большей, чем непосредственное вхождение).
Кроме того, просто ItemId проверять не совсем корректно - вполне может быть ситуация, когда номенклатура одна, а конфигурации разные (из одной номенклатуры изготавливаем её подобие, но немного отличающееся) тогда это не зацикливание.
Если учесть конфигурационные группы, периоды действия строки спецификации, тип строки спецификации (например, фантомная может разворачиваться) и другие тонкости, то напрямую по таблице пробегать может быть не очень хорошей идеей. В стандартной Аксе есть классы BomSearch* и BOMHierarchy* там можно подсмотреть примеры.
Да, Вы правы. Работает только для простых вариантов.
В классах BomSearch* и BOMHierarchy* так и не разобрался. Как с ними правильно работать, есть мануал?
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Получить номер источника данных по имени (ax 2009) SuperStar88 DAX: Программирование 3 22.06.2018 13:36
dynamicsaxse: November 2017 Release – Dynamics AX 2012 R3 Blog bot DAX Blogs 0 08.12.2017 10:51
axforum blogs: Квест: Подружим Dynamics Ax 2009 Sp1 RU7 c SharePoint Foundation 2010 Blog bot DAX Blogs 4 16.10.2017 17:50
emeadaxsupport: AX Performance - Analyzing key SQL Server configuration and database settings Blog bot DAX Blogs 0 28.09.2015 14:11
axforum blogs: Квест: Подружим Dynamics Ax 2009 Sp1 RU7 c SharePoint Foundation 2010 - Этап 2 Blog bot DAX Blogs 0 12.07.2011 14:11

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

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 10:31.