|
19.06.2017, 18:18 | #1 |
Участник
|
Создал query в АОТ.
Сейчас код выглядит так. X++: query = new Query(querystr(myQuery)); qbdsItt = SysQuery::findOrCreateDataSource(query, tableNum(InventTransferTable)); qbdsItt.addRange(fieldnum(InventTransferTable, ReceiveDate)).value(strfmt('%1..%2', fromDate, toDate)); qbdsItt.addRange(fieldnum(InventTransferTable, TransferStatus)).value(QueryValue(InventTransferStatus::Received)); qbdsItt.addRange(fieldnum(InventTransferTable, InventLocationIdFrom)).value(inventLocationId); if (inventLocationType != InventLocationType::Standard) { qbdsInventLocationTo = SysQuery::findOrCreateDataSource(query, tableNum(InventLocation), tableNum(InventTransferTable)); qbrDataAreaId = qbdsInventLocationTo.addRange(fieldNum(InventLocation, DataAreaId)); qbrDataAreaId.value(strFmt('((%1.%3 = %4) || (%2.%3 = %4))', 'InventLocationTo', 'InventLocationFrom', fieldStr(InventLocation, InventLocationType), any2int(inventLocationType))); } //info(qbdsItt.ToString()); queryRun = new QueryRun(query); rowCount = SysQuery::countLoops(queryRun); Да этого момента в AOT query не создавал, так что прошу сильно шапками не закидывать. |
|
19.06.2017, 18:27 | #2 |
Участник
|
уже хорошо.
но можно лучше. SysQuery::findOrCreateDataSource(query добавляет в корень. и не задает связь, насколько я помню. создайте ВЕСЬ запрос в АОТ. избавьте себя от необходимости манипулировать с датасорсами. в коде устанавливайте только range.value. даю маячок - в АОТ можно создать ДВА запроса. один для InventLocationType::Standard, другой для прочих типов. |
|
19.06.2017, 18:52 | #3 |
Участник
|
В общем, код должен выглядеть примерно так:
X++: Query query = new Query(querystr(myQuery)); QueryBuildDataSource qbdsItt = query.datasourcetable(tableNum(InventTransferTable)); // никаких Create! только читаем QueryBuildDataSource qbdsIlTo = query.datasourcetable(tableNum(InventLocation),1); // первый по порядку. Или query.datasource("InventLocationTo") позволяет получить датасорс по имени QueryBuildDataSource qbdsIlFrom = query.datasourcetable(tableNum(InventLocation),2); // второй по порядку. Или query.datasource Debug::assert(qbdsItt); Debug::assert(qbdsIlTo); Debug::assert(qbdsIlFrom); qbdsItt.addRange(fieldnum(InventTransferTable, ReceiveDate)).value(SysQuery::range(fromDate, toDate)); qbdsItt.addRange(fieldnum(InventTransferTable, TransferStatus)).value(SysQuery::value(InventTransferStatus::Received)); // может быть, лучше сразу задать в запросе в АОТ qbdsItt.addRange(fieldnum(InventTransferTable, InventLocationIdFrom)).value(inventLocationId); if (inventLocationType != InventLocationType::Standard) { SysQuery::findOrCreateRange(qbdsIlTo, fieldNum(InventLocation, DataAreaId)) .value(strFmt('((%1.%3 = %4) || (%2.%3 = %4))', qbdsIlTo.name(), qbdsIlFrom.name(), fieldStr(InventLocation, InventLocationType), any2int(inventLocationType))); } //info(qbdsItt.ToString()); queryRun = new QueryRun(query); rowCount = SysQuery::countLoops(queryRun); Последний раз редактировалось mazzy; 19.06.2017 в 18:59. |
|
19.06.2017, 18:56 | #4 |
Участник
|
Да, насчет количества строк.
у меня нет под рукой акс4, но насколько я понимаю из текстового файла с запросом, вы не задали Relation между датасорсами. вот там и происходило декартово произведение. без InventTable в запросе получается три несвязанные таблицы, насколько я понимаю. как раз для понимания и нужен результат q.datasource().tostring(). |
|
19.06.2017, 22:24 | #5 |
Участник
|
Если брать исходный текст с Query, то можно попробовать указать fetch mode 1:1 явно у всех DS (кроме первого, разумеется).
Если я правильно понял задачу, требуется что-то типа такого: X++: Query q; QueryBuildDataSource qbdsIJT, qbdsIJTr, qbdsIL, qbdsIT; QueryBuildRange qbr; QueryRun qr; ; q = new Query(); // смысл group by мне непонятен qbdsIJT = q.addDataSource(tablenum(InventJournalTable)); // qbdsIJT.orderMode(OrderMode::GroupBy); qbdsIJT.addSelectionField(fieldNum(InventJournalTable, JournalId), SelectionField::Database); qbdsIJT.addSelectionField(fieldNum(InventJournalTable, InventLocationId), SelectionField::Database); qbdsIJT.addSelectionField(fieldNum(InventJournalTable, InventLocationIdTo), SelectionField::Database); qbdsIJT.addRange(fieldnum(InventJournalTable, JournalNameId)).value('ПРС'); qbdsIJTr = qbdsIJT.addDataSource(tablenum(InventJournalTrans)); qbdsIJTr.addSelectionField(fieldNum(InventJournalTrans, InventTransId), SelectionField::Database); qbdsIJTr.addSelectionField(fieldNum(InventJournalTrans, ItemId), SelectionField::Database); qbdsIJTr.addSelectionField(fieldNum(InventJournalTrans, InventDimId), SelectionField::Database); qbdsIJTr.addSelectionField(fieldNum(InventJournalTrans, Qty), SelectionField::Database); qbdsIJTr.relations(true); qbdsIJTr.joinMode(JoinMode::InnerJoin); // qbdsIJTr.orderMode(OrderMode::GROUPBY); qbdsIJTr.fetchMode(QueryFetchMode::One2One); qbdsIT = qbdsIJTr.addDataSource(tableNum(InventTable)); qbdsIT.relations(true); qbdsIT.addSelectionField(fieldNum(InventTable, ItemName), SelectionField::Database); qbdsIT.addSelectionField(fieldNum(InventTable, ItemGroupId), SelectionField::Database); qbdsIT.joinMode(joinMode::InnerJoin); // qbdsItl.orderMode(OrderMode::GROUPBY); qbdsIT.fetchMode(QueryFetchMode::One2One); // можно объединить 2 DS в одну конструкцию qbdsIT = qbdsIJT.addDataSource(tableNum(InventLocation)); qbdsIT.fetchMode(QueryFetchMode::One2One); qbdsIT.joinMode(JoinMode::ExistsJoin); qbdsIT.relations(false); // это на самом деле relation qbr = qbdsIT.addRange(fieldNum(InventLocation, InventLocationId)); qbr.value(strFmt('(%1.%2 = %4.%5) || (%1.%3 = %4.%5)', qbdsIJT.name(), fieldStr(InventJournalTable, InventLocationId), fieldStr(InventJournalTable, InventLocationIdTo), qbdsIT.name(), fieldStr(InventLocation, InventLocationId)) ); // прочие условия (на справочник складов) //qbdsIT.addRange(fieldNum(... // проверка, что не потерялся какой-нибудь DS qr = new QueryRun(q); if (qr.next()) info(strFmt('%1 %2 %3', qr.get(tableNum(InventJournalTable)).(fieldNum(InventJournalTable, JournalId)), qr.get(tableNum(InventJournalTrans)).(fieldNum(InventJournalTrans, InventTransId)), qr.get(tableNum(InventTable)).(fieldNum(InventTable, ItemName)) )); info('DAX query: '+qbdsIJT.toString()); info(strFmt('Query qty: %1', SysQuery::qrCount(new QueryRun(q)))); P.S. В стандарте, конечно же, нет полей со складами в шапке скл.журналов, добавлены вручную. Пока строчил, уже всё порешали))) Последний раз редактировалось dim-gin; 19.06.2017 в 22:28. Причина: опоздал с сообщением |
|
|
За это сообщение автора поблагодарили: mazzy (2), smailik (1), alex55 (1). |
19.06.2017, 22:32 | #6 |
Участник
|
group by там похоже, потому что они что-то считают (судя по промелькнувшему SysQuery::count)
похоже просто код не полный. да, проблема как раз в нескольких existsJoin в подчиненных таблицах. с одним existsJoin никаких проблем Цитата:
Сообщение от dim-gin
X++: // можно объединить 2 DS в одну конструкцию qbdsIT = qbdsIJT.addDataSource(tableNum(InventLocation)); qbdsIT.fetchMode(QueryFetchMode::One2One); qbdsIT.joinMode(JoinMode::ExistsJoin); qbdsIT.relations(false); // это на самом деле relation qbr = qbdsIT.addRange(fieldNum(InventLocation, InventLocationId)); qbr.value(strFmt('(%1.%2 = %4.%5) || (%1.%3 = %4.%5)', qbdsIJT.name(), fieldStr(InventJournalTable, InventLocationId), fieldStr(InventJournalTable, InventLocationIdTo), qbdsIT.name(), fieldStr(InventLocation, InventLocationId)) ); // прочие условия (на справочник складов) опять же скорее всего, нам не все условия показали, а только самое тривиальное. и если условия в ТЗ будут углублены и расширены (а они будут углублены) то такой маневр будет оооочень сильно мешать. |
|
19.06.2017, 22:44 | #7 |
Участник
|
2 mazzy:
Да, это не самое элегантное решение. Но разве исходные 2 exists join'а с OR намного проще в выполнении для БД? Или Вы подразумеваете другой смысл под словом "мешать"? Последний раз редактировалось dim-gin; 19.06.2017 в 22:45. Причина: опечатка |
|
19.06.2017, 23:00 | #8 |
Участник
|
для БД не проще.
мешать будет человеку. если сейчас условие упаковать в один existJoin, то с появлением новых условий на склады, условие придется делать все более навороченным и сильно непонятным и для программиста, и для пользователя. пользователь появляется поскольку часто готовый query может оказаться в стандартном диалоге, где пользователь может его подправить. даже опытный пользователь повесится. придется делать этот range::Locked. а затем придумывать обходные пути чтобы таки как-то разрешить. да, из кода видно, что в данном случае разработчики не парятся с критериями, а используют диалог с единственным значением для фильтра в каждом range. и хорошо, если это значение можно подставить из выпадающего списка ))) но рано или поздно они могут захотеть таки перейти на полноценные критерии вместо единственного значения. этот workaround сделает любое расширение условия по складам очень нетривиальным и сложным. |
|
|
За это сообщение автора поблагодарили: dim-gin (1). |