12.09.2011, 10:56 | #1 |
Участник
|
вопрос по Query
Простейшая задача: есть query по таблице CustTable с какими-то условиями.
Есть значение "КлиентАБВ". Нужно проверить, есть ли запись с таким значением поля AccountNum в имеющемся query. Понято, через queryRun.next() можно перебрать все записи и условием проверить, но хотелось бы по быстрей и покрасивей. |
|
12.09.2011, 11:09 | #2 |
Участник
|
А что если создать копию этого query и добавить туда ренж по AccountNum, много перебирать не надо, поле уникальное – достаточно одного одного queryRun.next().
__________________
Не принимайте жизнь всерьез - это временное явление... |
|
12.09.2011, 11:11 | #3 |
Участник
|
В общем случае подцепить к имеющемуся query ещё один CustTable с типом связи exists join и наложить уже на него условие "КлиентАБВ". Затем, сделав один раз queryRun.next(), посмотреть вернулось ли что-нибудь.
to Jorj: если в исходном query на поле AccountNum уже есть условие, то ещё одно условие "КлиентАБВ". добавится к нему через "ИЛИ". Ещё вариант, чтобы добится присоединения условия через "И",можно воспользоваться "расширенным синтаксисом" range (http://www.axaptapedia.com/Expressions_in_query_ranges) и добавить условие "КлиентАБВ" через какое-нибудь свободное поле (например через recid. Но и тогда в общем случае могут возникнуть проблемы совместимости, например при наличии RLS: Что делает RLS с связанными запросами в отчете). Последний раз редактировалось S.Kuskov; 12.09.2011 в 12:57. |
|
12.09.2011, 11:20 | #4 |
Участник
|
Цитата:
X++: boolean findSuperCust(Query _srcQuery, CustAccount _custAccount = "КлиентАБВ") { Query q = new Query(q); // создаем копию QueryRun qr; // устанавливаем новый критерий или меняем существующий findOrCreateRange_W(q.dataSourceTable(tablenum(custTable)),fieldnum(custTable, AccountNum), QueryValue(_custAccount)); // выполняем запрос qr = new QueryRun(q); return qr.next(); } |
|
12.09.2011, 11:37 | #5 |
Участник
|
Цитата:
Вы о каких эфектах? В случае если пользовательский фильтр по полю accountNum имеет место быть, то тогда просто взять и заменить его на "КлиентАБВ" можно только если истинно Global::inRange(Range.value, "КлиентАБВ"). В общем случае пользовательских фильтров может быть несколько, значит проверить прийдётся их все, т.е. нужен цикл. ИМХО добавить ещё одну связку по exists join будет проще. Ещё раз. Все эти извращения нужны если "пользовательский фильтр по полю accountNum имеет место быть". Если нет, то достаточно совета Jorj и mazzy |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
12.09.2011, 11:45 | #6 |
Участник
|
Цитата:
В принципе, общая идея, заключающаяся в том, что нужно наложить еще один Range по этому полю - правильная. Проблема только в том, что этот Range должен подкючаться по "И", а если уже есть Range по этому же полю, скажем, настроенный пользователем, то подключение произойдет по "ИЛИ" Именно для данного конкретного случая можно сделать "хитрый трюк". Дело в том, что определение того факта, что Range добавляется по уже существующему полю выполняется по Id поля. При этом, как правило, используется FieldId. Однако Axapta может идентифицировать поле как по FieldId, так и по ExtendedFieldId. Т.е. идентифицировать поле, как первый элемент массива. Естесственно, что FieldId и ExtendedFieldId - это разные значения. Как следствие, построитель запросов интепретирует их как разные Range и выполняет объединение по "И". Получается, примерно следующее X++: static void Job_Test(QueryRun queryRun) { Query queryFind; QueryRun queryRunFind; QueryBuildDataSource qbds; QueryBuildRange qbr; ; queryFind = new Query(queryRun.query().pack()); qbds = queryFind.dataSourceTable(tablenum(CustTable)); // Вот этот трюк qbr = qbds.findRange(fieldnum(CustTable, accountNum)); if (qbr) { // Если Range уже есть, то создаю новый Range по ExdendendFieldId qbr = qbds.addRange(fieldId2ext(fieldnum(CustTable, accountNum),1)); } qbr.value('КлиентАБВ'); queryRunFind = new QueryRun(queryFind); if (queryRunFind.next()) { info("Есть такая запись"); } } Естесственно, этот трюк работает только для полей, которые массивами не являются. Для полей-массивов можно сделать подобное только для первого элемента массива. |
|
|
За это сообщение автора поблагодарили: coolibin (1), S.Kuskov (1), propeller (1). |
12.09.2011, 12:41 | #7 |
Участник
|
Цитата:
Если выбирать из предложенных вариантов, то мне больше нравится мой про использование http://www.axaptapedia.com/Expressions_in_query_ranges P.S.: propeller, вот уж действительно "простейшая задача" Последний раз редактировалось S.Kuskov; 12.09.2011 в 13:32. |
|
12.09.2011, 13:32 | #8 |
Участник
|
Если ровно один, то findOrCreateRange_W изменит критерий на 'КлиентАБВ' по полю.
Если меньше одного, то findOrCreateRange_W добавит критерий 'КлиентАБВ' по полю. А вот если больше одного, то findOrCreateRange_W изменит один из критериев (первый попавшийся) на 'КлиентАБВ'. Все критерии по этому полю будут действовать через ИЛИ. Цитата:
А ведь точно. |
|
12.09.2011, 14:31 | #9 |
Участник
|
мне кажется что достаточно будет добавить ",КлиентАБВ", если критерий уже существует.
X++: boolean findSuperCust(Query _srcQuery, CustAccount _custAccount = "КлиентАБВ") { Query q = new Query(_srcQuery); // создаем копию QueryBuildRange qbr; QueryRun qr; // устанавливаем новый критерий или меняем существующий qbr = SysQuery::findOrCreateRange(q.dataSourceTable(tablenum(custTable)),fieldnum(custTable, AccountNum)); qbr.value( queryRangeConcat(qbr.value(), _custAccount) ); // добавляем к уже существующему или устанавливаем вместо пустого // выполняем запрос qr = new QueryRun(q); return qr.next(); } |
|
12.09.2011, 14:39 | #10 |
Участник
|
queryRangeConcat() - это условие 'или'
Кроме того, кто может поручиться, что ранее добавленное условие - это не расширенный фильтр?
__________________
Axapta v.3.0 sp5 kr2 |
|
12.09.2011, 14:48 | #11 |
Участник
|
ок. убедили.
вариант S.Kuskov: приджойнить exist join тоже не подойдет. поскольку в запросе уже может быть join. http://msdn.microsoft.com/en-us/libr...36(AX.10).aspx тогда остается только перебор записей в случае, если критерий на accountNum установлен? |
|
12.09.2011, 15:18 | #12 |
Участник
|
похоже вот такой способ будет работать всегда.
но если на код клиента уже был установлен критерий, то этот способ будет работать медленно. X++: boolean findSuperCust(Query _srcQuery, CustAccount _custAccount = "КлиентАБВ") { Query q = new Query(_srcQuery); // создаем копию QueryBuildRange qbr; QueryRun qr; CustTable custTable; // устанавливаем новый критерий только если раньше он был не установлен. qbr = SysQuery::findOrCreateRange(q.dataSourceTable(tablenum(custTable)),fieldnum(custTable, AccountNum)); if( !qbr.value() ) qbr.value(queryValue(_custAccount)); // выполняем запрос qr = new QueryRun(q); while( qr.next() ) { custTable = qr.get(tablenum(CustTable)); if( custTable.accountNum == _custAccount ) return true; } return false; } |
|
12.09.2011, 15:44 | #13 |
Участник
|
Цитата:
X++: boolean findSuperCust(Query _srcQuery, CustAccount _custAccount = "КлиентАБВ") { Query q = new Query(_srcQuery); // создаем копию QueryBuildDataSource qbds = q.dataSourceTable(tablenum(custTable)); QueryBuildRange qbr; QueryRun qr; Range SuperCustRange = strfmt("(%1.%2 == %3)", qbds.name(), fieldStr(custTable, AccountNum)); // устанавливаем новый критерий или меняем существующий qbr = SysQuery::findOrCreateRange(qbds ,fieldnum(custTable, DataAreaId)); if (qbr.value()) qbr.value(strfmt("(%1 && %2)", SuperCustRange, qbr.value())); else qbr.value(SuperCustRange); // выполняем запрос qr = new QueryRun(q); return qr.next(); } |
|
12.09.2011, 16:06 | #14 |
Участник
|
Хм.
А что, уже стало возможно использовать совместно расширенный синтаксис фильтров и обычный?
__________________
Axapta v.3.0 sp5 kr2 |
|
|
За это сообщение автора поблагодарили: S.Kuskov (1). |
12.09.2011, 16:08 | #15 |
Участник
|
|
|
12.09.2011, 17:28 | #16 |
Участник
|
Можно попробовать добавить явный критерий по RecId искомой записи клиента, если он не используется в запросе (обычно не используется ).
Если используется, то через расширенный фильтр по аналогии с кодом клиента описанной выше у S.Kuskov. Или напрямую распарсить критерии по RecId и либо найти в них искомый и оставить только его либо выдать облом Последний раз редактировалось Alexius; 12.09.2011 в 17:32. |
|
13.09.2011, 08:44 | #17 |
Участник
|
Цитата:
Я тут ещё один чисто теоретический способ придумал . Как понятно из обсуждения, основной проблемой является сложность присоединения, в случае уже имеющегося условия, нового контрольного условия по "И". Вот я и подумал раз уж это так проблемно, то пусть оно себе присоединяется по "ИЛИ". В результате исходный запрос изменится и это изменение можно будет анализировать. В случае если количество строк возвращаемое запросом (можно посчитать при помощи SysQuery::countTotal) станется прежним, это будет означать (конечно с определёнными ограничениями), что новое условие по ИЛИ никак не повлияло на выборку, а следовательно исходный запрос содержал в себе контрольное условие. Что и требовалость орпределить Недостатки: на время анализа вся выборка должна быть заблокирована от корректировок для того чтобы исключить возможность изменения количества строк в запросе из вне. |
|
13.09.2011, 09:34 | #18 |
Участник
|
или не содержал И искомого значения в базе вообще нет.
не, не пойдет |
|
13.09.2011, 10:37 | #19 |
Участник
|
Цитата:
Пользователи его просто не видят в интерфейсе Кстати, никто не обращал внимание, что критерии со статусом Hidden - не такие уж и невидимые? Достаточно в форме расширенного фильтра вызвать расширенный фильтр (в 2009-й через комбинацию клавишь) и нажать Ok
__________________
Axapta v.3.0 sp5 kr2 |
|
13.09.2011, 11:21 | #20 |
Участник
|
Цитата:
Цитата:
Сообщение от Владимир Максимов
К сожалению, это ничего не гарантирует. Если исходный запрос относительно сложен и имеет несколько таблиц-источников с "не линейной" схемой объединения, то подключение еще одного источника по Exists Join может привести к тому, что запросу "снесет крышу". Результат может оказаться парадоксальным.
X++: boolean findSuperCust(Query _srcQuery, CustAccount _custAccount = "КлиентАБВ") { Query q; QueryRun qr; QueryBuildDataSource qbds,qbds2; ; q = new Query(_srcQuery); qbds = q.dataSourceTable(tablenum(custTable)); qbds2 = qbds.addDataSource(tablenum(custTable)); qbds2.fields().addField(fieldNum(custTable, AccountNum)); qbds2.fetchMode(JoinMode::INNERJOIN); qbds2.relations(true); qbds2.addRange(fieldNum(custTable, AccountNum)).value(_custAccount); qr = new QueryRun(q); return qr.next(); } |
|
|
За это сообщение автора поблагодарили: S.Kuskov (1). |
Теги |
query, как правильно |
|
Похожие темы | ||||
Тема | Ответов | |||
Очередной вопрос про Query | 45 | |||
Вопрос по query? | 1 | |||
Вопрос по query и join | 2 | |||
Вопрос по запросу (query) | 2 | |||
Вопрос знатокам QBE и Query в AXAPTA | 6 |
|