16.07.2010, 10:54 | #1 |
Участник
|
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 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); 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 |
Участник
|
1.
Понимает. Отлично понимает "два join". Неправильно делаете. Уж сколько раз твердилось: перестаньте программировать запросы с нуля. накидайте в 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(...); ... } здесь неоднократно говорилось о влиянии порядка условий в запросе на производительность. некоторые считают это мифом. некоторые, как я, считают порядок условий - важной вещью. я бы поредомендовал все-таки во всем коде придерживаться единого порядка в условиях. условие сначала по CustTable, потом по SalesID, потом по InventQtyReserv... это что-то уникальное, наверняка, нигде не закэшированное. мало того, этот уникальный запрос может выкинуть из кэша что-нибудь нужное и достаточно часто используемое. пишите единообразно. 5. (возможная причина ошибки) Кроме того, условие ">0" в критериях записывается по другому "0..". =============== В общем, сначала набросайте запрос мышкой в AOT. Проверьте. Уж потом, если захочется, ваяйте ваш код по созданию запроса и по закату солнца вручную. |
|
16.07.2010, 11:25 | #3 |
Участник
|
Да, эта проблема в тройке давно известна. Попробуйте перестроить запрос примерно так:
SalesLine --> SalesTable --> CustTable |
|
16.07.2010, 11:26 | #4 |
Участник
|
о_О!
|
|
16.07.2010, 11:42 | #5 |
Участник
|
... ну, или попробовать fetchMode(1:1)
|
|
16.07.2010, 11:46 | #6 |
Участник
|
Цитата:
если честно, то по-моему, в коде полная фигня написана.
но разбираться ни сил, ни желания. Задание: Нужно выбрать все открытые заказы у которых существует хотя бы одна строка с зарезервированным количеством != 0 И чтобы не делать каждый раз CustTable::Find() нужно при'join'ить CustTable Цитата:
не понимает "два exists join".
Цитата:
вкратце: не используйте exists join без необходимости. не надо с его помощью эмулировать left join.
Цитата:
здесь неоднократно говорилось о влиянии порядка условий в запросе на производительность.
Код: Но вам скорее всего нужно писать "!0" Цитата:
В общем, сначала набросайте запрос мышкой в AOT.
Проверьте. Уж потом, если захочется, ваяйте ваш код по созданию запроса и по закату солнца вручную. Код: SELECT * FROM SalesTable WHERE ((SalesStatus = Открыто)) |
|
16.07.2010, 11:50 | #7 |
Участник
|
вон tricky советует, попробуйте и отпишитесь... я о такой проблеме не в курсе, возможно он дело говорит.
К тому же датасорцев там ТРИ, а не один. На каждую таблицу по одному |
|
16.07.2010, 11:51 | #8 |
Ищущий знания...
|
Цитата:
т.е.: 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 |
Ищущий знания...
|
вот джобик для ясности (возможно будет понятней):
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 |
Участник
|
может быть как то так:
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 |
Участник
|
Цитата:
Сообщение от 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 |
Участник
|
|
|
16.07.2010, 13:04 | #13 |
Участник
|
угу. не бывает плохих вопросов, бывают плохие ответы
Цитата:
но если уж так хочется при'join'ить, то (см. ниже) Цитата:
|
|
16.07.2010, 13:15 | #14 |
Участник
|
хотя...
кашперук советует всегда 1:1 Связывание источников данных в запросах |
|
16.07.2010, 13:57 | #15 |
Участник
|
похоже первым ответ дал Dron aka Andy в далеком 2005 году
Join трех таблиц (две к одной) |
|
16.07.2010, 14:17 | #16 |
Axapta
|
Похоже, первыми были наши далекие предки.
Вопрос знатокам QBE и Query в AXAPTA Древовидная структура источников данных в Query |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
Теги |
join, query, как правильно |
|
|