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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 13.02.2013, 10:50   #1  
Xardas is offline
Xardas
Участник
 
28 / 13 (1) ++
Регистрация: 19.09.2012
Меняющийся тип соединения таблиц
Доброго времени суток.

Имеется класс с большим количеством запросов вида
X++:
select tbl1
exists join tbl2
where tbl2.field1 == tbl1.field1
Сейчас возникла необходимость модифицировать данный код:
Если значение некоторой логической переменной истина, то соединение таблиц должно производиться с помощью exists join.
Если значение этой же логической переменной ложь, то соединение должно производиться с помощью notexists join.

Можно ли произвести данную модификацию? Вариант
X++:
if (flag)
  select...
else
  select...
не устраивает, поскольку код будет раздут до неимоверных размеров с дублированием операторов, заключенных внутри while select.
Спасибо.
Старый 13.02.2013, 10:58   #2  
user_ax is offline
user_ax
Участник
Аватар для user_ax
 
599 / 39 (3) +++
Регистрация: 07.10.2012
Адрес: ZP
А через switch?
Старый 13.02.2013, 11:04   #3  
Xardas is offline
Xardas
Участник
 
28 / 13 (1) ++
Регистрация: 19.09.2012
Цитата:
Сообщение от user_ax Посмотреть сообщение
А через switch?
Не вижу принципиальной разницы между switch и if для тестирования значения логической переменной (принимающей всего 2 значения) за исключением того, что в switch придется писать еще case и break.

Вся проблема в том, что запросы идентичны за исключением exists и notexists.

Возможно, это реализуемо с помощью макроса?
Старый 13.02.2013, 11:07   #4  
Evgeniy2020 is offline
Evgeniy2020
Участник
 
309 / 68 (3) ++++
Регистрация: 10.04.2007
Адрес: Москва, САО, СЗАО
создавайте выборку программно через Query, QueryBuildDatasource
код будет более компактный
Старый 13.02.2013, 11:14   #5  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,496 / 1071 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Если query не нравится, то вариант
X++:
if (flag)
  select tableName ...
else
  select tableName ...

while tableName 
{

  next tableName;
}
вполне нормальный.
За это сообщение автора поблагодарили: Xardas (1).
Старый 13.02.2013, 11:42   #6  
Xardas is offline
Xardas
Участник
 
28 / 13 (1) ++
Регистрация: 19.09.2012
для Evgeniy2020:
На данный момент в коде множество запросов, и они все разные. Их объединяет только наличие exists join ко второй таблице. Придется делать на каждый запрос свой Query.

для raz:
Да, так я избегу переписывания операторов, но запросы все равно придется дублировать.

Последний раз редактировалось Xardas; 13.02.2013 в 12:21.
Старый 13.02.2013, 12:15   #7  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,496 / 1071 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Цитата:
Сообщение от Xardas Посмотреть сообщение
Запросы разные. Их объединяет только наличие exists join. Придется делать на каждый запрос свой Query.
Зачем. Один запрос и по условию ставите разный joinMode.
Старый 13.02.2013, 13:58   #8  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
Можно использовать макроподстановки
Важно помнить что макроподстановка выполняется в момент компиляции, а не в момент исполнения !
X++:
#localmacro.select
#define.Arg(%1)
    Select tableName
        where ...
    #if.arg('exists') exists #endIF
    #if.arg('notexists') notexists #endIF
    join joinTableName
        where ...
#endmacro

static void Job(Args _args)
{       

    if (flag)
        #select('exists');
    else
        #select('notexists');

    while (tableName)
    {
    
        next tableName;
    }
}
Если один и тот же запрос используется разных местах, можно оформить "глобальный" макрос в дереве AOT,
Нпример: \Macros\InventDimJoin
Старый 13.02.2013, 14:32   #9  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2925 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
Макрос можно покороче:
X++:
#localmacro.select
    Select tableName
        where ...
    %1
    join joinTableName
        where ...
#endmacro

static void Job(Args _args)
{       

    if (flag)
        #select(exists);
    else
        #select(notexists);

    while (tableName)
    {
    
        next tableName;
    }
}
За это сообщение автора поблагодарили: kair84 (1).
Старый 13.02.2013, 15:00   #10  
Xardas is offline
Xardas
Участник
 
28 / 13 (1) ++
Регистрация: 19.09.2012
Цитата:
Сообщение от kair84 Посмотреть сообщение
Важно помнить что макроподстановка выполняется в момент компиляции, а не в момент исполнения !
Вот это и настораживает.
Получается, что макросы в принципе нединамические. Как бы макрос не был написан, в конкретном месте основной программы все равно будет либо exists, либо notexists.

Цитата:
Сообщение от twilight Посмотреть сообщение
Еще как вариант можно join из запросов вообще убрать. А есть ли запись в связанной таблице проверять отдельно.
Это вообще не вариант. Представляете, как упадет производительность данного кода?

Похоже, придется использовать вариант
X++:
if (flag)
  select...
else
  select...
Что же, спасибо всем за уделенное время.
Старый 13.02.2013, 15:26   #11  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,715 / 1204 (44) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от twilight Посмотреть сообщение
Еще как вариант можно join из запросов вообще убрать. А есть ли запись в связанной таблице проверять отдельно.
Цитата:
Сообщение от Xardas Посмотреть сообщение
Это вообще не вариант. Представляете, как упадет производительность данного кода?
Далеко не факт. Это надо проверять экспериментально. Как раз тот случай, когда "теоретические" рассуждения не могут дать однозначный ответ. Надо проверять.

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

Кстати, ведь по описанному Вами условию, Вы имеет "зеркальные" выборки. Это значит, что если Exists будет выполняться быстро, то not Exists неизбежно будет выполняться медленно. Или наоборот. И далеко не факт, что перенесение проверки внутрь цикла существенно повлияет на среднее время выполнения. Повторюсь, это проверить надо.

А "в общем случае" рассуждения на подобную тему мало полезны. Именно в силу того, что неизвестны детали задачи. Вполне возможно, что задачу можно решить и без использования Exists просто модифицировав запрос. Однако без знания конкретной постановки задачи заранее сказать нельзя можно это сделать или нет.
__________________
- Может, я как-то неправильно живу?!
- Отчего же? Правильно. Только зря...
Старый 13.02.2013, 20:46   #12  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5813 (201) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Цитата:
Сообщение от Xardas Посмотреть сообщение
Имеется класс с большим количеством запросов вида
X++:
select tbl1
exists join tbl2
where tbl2.field1 == tbl1.field1
Сейчас возникла необходимость модифицировать данный код: Если значение некоторой логической переменной истина, то соединение таблиц должно производиться с помощью exists join. Если значение этой же логической переменной ложь, то соединение должно производиться с помощью notexists join. Можно ли произвести данную модификацию?
Есть время разбрасывать камни и время их собирать. Кто-то поленился нормально написать код, избавиться от дублирования, вынести принятие однотипных решений в одно место, а теперь придется либо наплодить кучу copy-paste'а, либо засучить рукава и провести серьезный рефакторинг кода.
Цитата:
Сообщение от Xardas Посмотреть сообщение
Похоже, придется использовать вариант
X++:
if (flag)
  select...
else
  select...
Что же, спасибо всем за уделенное время.
Не стоит так делать. Тут уже писали, наиболее нормальный вариант, позволяющий менять тип join'а во время выполнения, - это переписать код на Query'ках. Решать проблему copy-paste'ом - все равно, что заметать сор под половик в надежде, что убирать его придется кому-то другому; это непрофессионально, в конце концов
За это сообщение автора поблагодарили: S.Kuskov (1).
Старый 13.02.2013, 17:17   #13  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от kair84 Посмотреть сообщение
Можно использовать макроподстановки
Не надо использовать макросы (если это не константы)
причины уже назыавали.
Старый 13.02.2013, 15:01   #14  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
650 / 352 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Цитата:
Сообщение от Xardas Посмотреть сообщение
для Evgeniy2020:
На данный момент в коде множество запросов, и они все разные. Их объединяет только наличие exists join ко второй таблице. Придется делать на каждый запрос свой Query.

для raz:
Да, так я избегу переписывания операторов, но запросы все равно придется дублировать.
Используйте QueryBuildDataSource и разбейте на методы. Если все грамотно сделать, дублирования кода не будет. Все будут сыты и довольны.
__________________
// no comments
Старый 13.02.2013, 15:19   #15  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
2 Xardas
в данном случае макроподстановка - это способ уменьшить количество кода
PHP код:
if (flag)
  
select...
else
  
select... 
а в зависимости от "размера" оператора select, возможно и нагляднее будет, сразу будет видно что отличие только в способе связывания
Старый 13.02.2013, 14:09   #16  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,448 / 1792 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Когда речь заходит об оптимизации не самого кода, а процесса его написания, на первый план выходят такие критерии как наглядность, модифицируемость, маштабируемость.
Единственное достоинство оператора select - нагладность, при использовании макросов пропадает. Уж лучше Query.
Старый 13.02.2013, 14:34   #17  
twilight is offline
twilight
MCTS
MCBMSS
 
890 / 241 (10) ++++++
Регистрация: 17.10.2004
Адрес: Королёв
Еще как вариант можно join из запросов вообще убрать. А есть ли запись в связанной таблице проверять отдельно.
__________________
I could tell you, but then I would have to bill you.
Старый 13.02.2013, 14:50   #18  
kair84 is offline
kair84
Участник
 
47 / 58 (2) ++++
Регистрация: 15.04.2010
Адрес: Belarus
S.Kuskov - согласен не наглядно, сам обычно использую в таких случаях Query, предложил как вариант, т.к. топикстартер отверг все предыдущие варианты. а вот с точки зрения модифицируемости - вполне.

Последний раз редактировалось kair84; 13.02.2013 в 14:54.
Старый 14.02.2013, 12:49   #19  
Xardas is offline
Xardas
Участник
 
28 / 13 (1) ++
Регистрация: 19.09.2012
Зря вы иронизируете. Может, вы не поняли, но запросы в коде разные. Специально для вас подчеркиваю это слово.
Нужен пример? Да запросто.
Первый запрос:
X++:
while select tbl1
      group by EmplId, Organization
      where tbl1.PostDate >= startPeriod &&
            tbl1.PostDate <= endPeriod &&
            tbl1.Organization like organization + "*"
        exists join tbl2
        where tbl2.Key  == tbl1.Key &&
              tbl2.Sham == NoYes::No
Второй запрос:
X++:
select sum(Amount)
from tbl1
group by EmplId
where tbl1.PostDate     <  startPeriod &&
      tbl1.EmplId       == temp.EmplId &&
      tbl1.Organization == temp.Organization
  exists join tbl2
  where tbl2.Key  == tbl1.Key &&
        tbl2.Sham == NoYes::No;
И таких запросов несколько.
Ну и как тут обойтись одной кверей? Для каждого запроса менять ее?
Старый 14.02.2013, 13:08   #20  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
Цитата:
Сообщение от Xardas Посмотреть сообщение
Ну и как тут обойтись одной кверей? Для каждого запроса менять ее?
X++:
Query query = new Query();
QueryBuildDataSource qbds, qbdsJoin;

boolean groupByEmplId, groupByOrg;
boolean sumAmountField;
boolean selectForEmplId;
boolean needJoin;
;

qbds = query.addDataSource(tableNum(tbl1));
qbds.OrderMode(OrderMode::GroupBy);

if (needJoin)
{
   qbdsJoin =  qbds.addDataSource(tableNum(tbl2));
   qbdsJoin.relations(true);
}

if (groupByEmplId)
      qbds.addSortField(fieldNum(tbl1, EmplId));

if (groupByOrg)
      qbds.addSortField(fieldNum(tbl1, Organization));

if (selectForEmplId)
   qbds.addRange(fieldNum(tbl1, EmplId)).value(queryValue(temp.EmplId));

if (sumAmountField)
   qbds.addSelectionField(fieldNum(tbl1, Amoun), SelectionField::Sum);

// и т.д. и т.п ....
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
AX 2012 Наследование таблиц. Краткое описание механизма sukhanchik DAX: Программирование 32 21.09.2018 17:56
Таблица, расширенный тип данных, базовый перечислимый тип или класс, вызванные test_Sdelka, уже существуют. Импортирование Table прервано. Poleax DAX: Программирование 4 17.05.2011 17:57
Тип производственного заказа Anais DAX: Функционал 17 26.05.2005 13:50
Никак не могу вьехать, для чего нужны тип счета и тип разноски maloy DAX: Функционал 5 28.03.2004 17:18
Тип связи Андре DAX: Программирование 9 25.04.2002 20:20
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра
Комбинированный вид Комбинированный вид

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

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

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