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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 16.07.2010, 10:54   #1  
Roman N. Krivov is offline
Roman N. Krivov
Участник
 
25 / 11 (1) +
Регистрация: 04.05.2010
Адрес: Мир, Россия, Московская область
QueryRun и два Join'а
Доброго времени суток!

Столкнулся со следующей проблемой: QueryRun не понимает два join к одному datasource.

Есть запрос:
Код:
 select * from SalesTable
join CustTable on CustTable.AccountNum == SalesTable.CustAccount
join SalesLine on SalesLine.SalesId == SalesTable.SalesId
where SalesTable.SalesStatus == SalesStatus::Backorder &&
SalesLine.InventQtyReserve <> 0
Нужно такой же запрос организовать в QueryRun. Вот что я делаю:
X++:
    #define.RecId('RecId')
    Query                   query = new Query();

    QueryBuildDataSource    qbdsSalesTable;
    QueryBuildDataSource    qbdsCustTable;
    QueryBuildDataSource    qbdsSalesLine;
    ;

    qbdsSalesTable = SysQuery::findOrCreateDatasource(query, tablenum(SalesTable));
    qbdsCustTable = SysQuery::findOrCreateDatasource(query, tablenum(CustTable), tablenum(SalesTable), false);
    qbdsSalesLine = SysQuery::findOrCreateDatasource(query, tablenum(SalesLine), tablenum(SalesTable), false);

    qbdsCustTable.addLink(fieldnum(SalesTable, CustAccount), fieldnum(CustTable, AccountNum));

    qbdsSalesLine.joinMode(JoinMode::ExistsJoin);
    qbdsSalesLine.fields().dynamic(boolean::false);
    qbdsSalesLine.fields().clearFieldList();
    qbdsSalesLine.addSelectionField(fieldname2id(qbdsSalesLine.table(), #RecId));

    SysQuery::findOrCreateRange(qbdsSalesLine, fieldnum(SalesLine, InventQtyReserv)).value(SysQuery::valueNot(0));

    qbdsSalesLine.addLink(fieldnum(SalesTable, SalesId), fieldnum(SalesLine, SalesId));

    SysQuery::findOrCreateRange(qbdsSalesTable, fieldnum(SalesTable, SalesStatus)).value(SysQuery::value(SalesStatus::Backorder));

    SysQuery::findOrCreateRange(qbdsSalesTable, fieldnum(SalesTable, TotalAmountCurReserve)).value('> 0');

    queryRun = new QueryRun(query);
В результате qbdsSalesTable оказывается вообще без join'ов. Как это можно вылечить?

Microsoft Businness Solutions-Axapta 3.0 Build #1951.3730/514-193 SP3/OP023-71

Последний раз редактировалось Roman N. Krivov; 16.07.2010 в 10:57.
Старый 16.07.2010, 11:17   #2  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
1.
Понимает. Отлично понимает "два join".
Цитата:
Сообщение от Roman N. Krivov Посмотреть сообщение
Вот что я делаю:
....
Как это можно вылечить?
Неправильно делаете.
Уж сколько раз твердилось: перестаньте программировать запросы с нуля.
накидайте в AOT, а в коде используйте
myQuery = new Query(querystr(myAOTQuery));

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

Поэтому совет: прежде чем жаловаться "не понимает", сначала проверьте по AOT.

2.
не понимает "два exists join".
об этом писалось на форуме. неоднократно. и способы решения приводились. ищите.

вкратце: не используйте exists join без необходимости. не надо с его помощью эмулировать left join.

3.
в аксапте есть режим кэширования. разберитесь с ним. ОБЯЗАТЕЛЬНО!
из-за кэширования зачастую лучше писать не один суперзапрос, а простой запрос и несколько вложенных.

Кроме того, помните о том, что Аксапта очень активно использует кэширование планов запросов на SQL.
Поэтому лучше писать простые и единообразные запросы.

В частности у вас, скорее всего, возможно лучше написать код, работающий по следующей схеме:

X++:
while select salesTable
    join salesLine
    where salesLine.SalesId == salesTable.SalesId
{
    ...
    CustTable = CustTable::find(...);
    ...
}
4. (опционально)
здесь неоднократно говорилось о влиянии порядка условий в запросе на производительность.
некоторые считают это мифом.
некоторые, как я, считают порядок условий - важной вещью.

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

пишите единообразно.

5. (возможная причина ошибки)
Кроме того, условие ">0" в критериях записывается по другому "0..".

===============
В общем, сначала набросайте запрос мышкой в AOT.
Проверьте.
Уж потом, если захочется, ваяйте ваш код по созданию запроса и по закату солнца вручную.
__________________
полезное на axForum, github, vk, coub.
Старый 16.07.2010, 11:25   #3  
tricky is offline
tricky
Участник
 
140 / 64 (3) ++++
Регистрация: 03.05.2005
Адрес: Гуково
Да, эта проблема в тройке давно известна. Попробуйте перестроить запрос примерно так:
SalesLine --> SalesTable --> CustTable
Старый 16.07.2010, 11:26   #4  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от tricky Посмотреть сообщение
Да, эта проблема в тройке давно известна. Попробуйте перестроить запрос примерно так:
SalesLine --> SalesTable --> CustTable
о_О!
__________________
полезное на axForum, github, vk, coub.
Старый 16.07.2010, 11:42   #5  
tricky is offline
tricky
Участник
 
140 / 64 (3) ++++
Регистрация: 03.05.2005
Адрес: Гуково
... ну, или попробовать fetchMode(1:1)
Старый 16.07.2010, 11:46   #6  
Roman N. Krivov is offline
Roman N. Krivov
Участник
 
25 / 11 (1) +
Регистрация: 04.05.2010
Адрес: Мир, Россия, Московская область
Цитата:
если честно, то по-моему, в коде полная фигня написана.
но разбираться ни сил, ни желания.
Плохо когда не пытаются разобраться.

Задание:
Нужно выбрать все открытые заказы у которых существует хотя бы одна строка с зарезервированным количеством != 0 И чтобы не делать каждый раз CustTable::Find() нужно при'join'ить CustTable

Цитата:
не понимает "два exists join".
Тут не "два exists join", а "inner join + exists join"
Цитата:
вкратце: не используйте exists join без необходимости. не надо с его помощью эмулировать left join.
А никто и не пытается эмулировать? Да и зачем, если left join и так хорошо работает?
Цитата:
здесь неоднократно говорилось о влиянии порядка условий в запросе на производительность.
В данном случае от перестановки условий запроса скорость не измениться
Код:
Но вам скорее всего нужно писать "!0"
Согласен, хотя зарезервированное кол-во всегда больше 0. Но во избежании проблем в будущем - исправил
Цитата:
В общем, сначала набросайте запрос мышкой в AOT.
Проверьте.
Уж потом, если захочется, ваяйте ваш код по созданию запроса и по закату солнца вручную.
Я "накидал" запрос в AOT'е и в результате получил:
Код:
SELECT * FROM SalesTable WHERE ((SalesStatus = Открыто))
В общем, не понимает он два join к одному datasource, как бы вы не старались
Старый 16.07.2010, 11:50   #7  
ddadream is offline
ddadream
Участник
Аватар для ddadream
 
130 / 17 (1) ++
Регистрация: 30.11.2001
Адрес: moscow
вон tricky советует, попробуйте и отпишитесь... я о такой проблеме не в курсе, возможно он дело говорит.

К тому же датасорцев там ТРИ, а не один. На каждую таблицу по одному
Старый 16.07.2010, 11:51   #8  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
Цитата:
Сообщение от Roman N. Krivov Посмотреть сообщение

В общем, не понимает он два join к одному datasource, как бы вы не старались
Вам выше написали, используйте QueryFetchMode::One2One

т.е.:
X++:
qbdsSalesTable = SysQuery::findOrCreateDatasource(query, tablenum(SalesTable));
qbdsSalesTable.fetchMode(QueryFetchMode::One2One);
    qbdsCustTable = SysQuery::findOrCreateDatasource(query, tablenum(CustTable), tablenum(SalesTable), false);
qbdsCustTable.fetchMode(QueryFetchMode::One2One);
    qbdsSalesLine = SysQuery::findOrCreateDatasource(query, tablenum(SalesLine), tablenum(SalesTable), false);
qbdsSalesLine.fetchMode(QueryFetchMode::One2One);
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
Старый 16.07.2010, 12:03   #9  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
вот джобик для ясности (возможно будет понятней):
X++:
Query                   query = new Query();
    QueryBuildDataSource    qbds1, qbds2, qbds3;
    ;

    qbds1 = query.addDataSource(tableNum(SalesTable));
    qbds1.fetchMode(QueryFetchMode::One2One);
    qbds2 = qbds1.addDataSource(tableNum(CustTable));
    qbds2.fetchMode(QueryFetchMode::One2One);
    qbds3 = qbds2.addDataSource(tableNum(SalesLine));
    qbds3.fetchMode(QueryFetchMode::One2One);

    qbds1.addRange(fieldNum(SalesTable, SalesId)).value(SysQuery::valueNotEmptyString());
    qbds2.addRange(fieldNum(CustTable, AccountNum)).value(QueryValue('Тест'));
    qbds3.addRange(fieldNum(SalesLine, ItemId)).value(QueryValue('Товар'));

    info(qbds1.toString());
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
Старый 16.07.2010, 12:22   #10  
ddadream is offline
ddadream
Участник
Аватар для ddadream
 
130 / 17 (1) ++
Регистрация: 30.11.2001
Адрес: moscow
может быть как то так:

X++:
static void Job2(Args _args)
{
    Query                   query;
    QueryRun                queryRun;
    QueryBuildDataSource    qbdsSalesTable;
    QueryBuildDataSource    qbdsCustTable;
    QueryBuildDataSource    qbdsSalesLine;

    QueryBuildRange           queryBuildRange;
    QueryBuildLink            queryBuildLink, queryBuildLink1;
    salestable  salestable;
    ;


    query = new Query();

    qbdsSalesTable = query.addDataSource(tablenum(SalesTable));

    queryBuildRange = qbdsSalesTable.addRange(fieldnum(SalesTable, SalesStatus));
    queryBuildRange.value( queryvalue(salesstatus::Backorder) );

    qbdsCustTable =  qbdsSalesTable.addDataSource(tablenum(CustTable));
    qbdsSalesLine =  qbdsSalesTable.addDataSource(tablenum(SalesLine));

    //qbdsCustTable.joinMode( 2 );
    //qbdsSalesLine.joinMode( 2 );
    
    qbdsSalesLine.fetchMode( QueryFetchMode::One2One );
    qbdsCustTable.fetchMode( QueryFetchMode::One2One );


    queryBuildLink = qbdsSalesLine.addLink(fieldnum(SalesTable, salesid),fieldnum(salesline, salesid));
    queryBuildLink1 = qbdsCustTable.addLink(fieldnum(SalesTable, custaccount),fieldnum(custtable, accountnum));

    queryRun = new QueryRun(query);


    while (queryRun.next())
    {
        salestable = queryRun.get(tablenum(Salestable));
        
        info (strfmt("salesid %1 - %2", salestable.salesid, salestable.RecId));
    }

}

Последний раз редактировалось ddadream; 16.07.2010 в 12:36.
Старый 16.07.2010, 12:24   #11  
Roman N. Krivov is offline
Roman N. Krivov
Участник
 
25 / 11 (1) +
Регистрация: 04.05.2010
Адрес: Мир, Россия, Московская область
Цитата:
Сообщение от lev Посмотреть сообщение
вот джобик для ясности (возможно будет понятней):
X++:
Query                   query = new Query();
    QueryBuildDataSource    qbds1, qbds2, qbds3;
    ;

    qbds1 = query.addDataSource(tableNum(SalesTable));
    qbds1.fetchMode(QueryFetchMode::One2One);
    qbds2 = qbds1.addDataSource(tableNum(CustTable));
    qbds2.fetchMode(QueryFetchMode::One2One);
    qbds3 = qbds2.addDataSource(tableNum(SalesLine));
    qbds3.fetchMode(QueryFetchMode::One2One);

    qbds1.addRange(fieldNum(SalesTable, SalesId)).value(SysQuery::valueNotEmptyString());
    qbds2.addRange(fieldNum(CustTable, AccountNum)).value(QueryValue('Тест'));
    qbds3.addRange(fieldNum(SalesLine, ItemId)).value(QueryValue('Товар'));

    info(qbds1.toString());
Такой вариант работает. Благодарю за помощь
Старый 16.07.2010, 12:29   #12  
Roman N. Krivov is offline
Roman N. Krivov
Участник
 
25 / 11 (1) +
Регистрация: 04.05.2010
Адрес: Мир, Россия, Московская область
Цитата:
Сообщение от lev Посмотреть сообщение
Вам выше написали, используйте QueryFetchMode::One2One
Просто не сразу заметил. Браузер не обновил страницу. Пришлось перезаходить.
Вариант c QueryFetchMode::One2One работает
Старый 16.07.2010, 13:04   #13  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Roman N. Krivov Посмотреть сообщение
Плохо когда не пытаются разобраться.
угу. не бывает плохих вопросов, бывают плохие ответы

Цитата:
Сообщение от Roman N. Krivov Посмотреть сообщение
И чтобы не делать каждый раз CustTable::Find() нужно при'join'ить CustTable
А это то зачем?
но если уж так хочется при'join'ить, то (см. ниже)

Цитата:
Сообщение от Roman N. Krivov Посмотреть сообщение
Я "накидал" запрос в AOT'е и в результате получил:
Код:
SELECT * FROM SalesTable WHERE ((SalesStatus = Открыто))
В общем, не понимает он два join к одному datasource, как бы вы не старались
а у меня получается. нисколько не старался.
Нажмите на изображение для увеличения
Название: 1.PNG
Просмотров: 541
Размер:	51.3 Кб
ID:	5964
__________________
полезное на axForum, github, vk, coub.
Старый 16.07.2010, 13:15   #14  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
хотя...
кашперук советует всегда 1:1 Связывание источников данных в запросах
__________________
полезное на axForum, github, vk, coub.
Старый 16.07.2010, 13:57   #15  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
похоже первым ответ дал Dron aka Andy в далеком 2005 году
Join трех таблиц (две к одной)
__________________
полезное на axForum, github, vk, coub.
Старый 16.07.2010, 14:17   #16  
oip is offline
oip
Axapta
Лучший по профессии 2014
 
2,564 / 1416 (53) ++++++++
Регистрация: 28.11.2005
Записей в блоге: 1
Похоже, первыми были наши далекие предки.

Вопрос знатокам QBE и Query в AXAPTA
Древовидная структура источников данных в Query
За это сообщение автора поблагодарили: mazzy (2).
Теги
join, query, как правильно

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Dynamics AX: QueryRun and Query Objects - Binding operation failed to allocate buffer space Blog bot DAX Blogs 0 03.04.2009 08:05
Простой QueryRun не работает miklenew DAX: Программирование 13 20.01.2009 14:17
OZKA's DAX Journal: Join между временной и постоянной таблицей через QueryRun. Blog bot DAX Blogs 12 14.01.2009 17:34
Воскрешение мумии ... или давно забытая история про два Outer Join Saber DAX: Программирование 3 28.11.2007 17:12
Глюки в Query с разными типами Join (в т.ч. NonExistsJoin) к одной таблице gl00mie DAX: Программирование 10 14.02.2007 13:22

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

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

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