AXForum  
Go Back   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Forgotten Your Password?
Register Forum Rules FAQ Members List Today's Posts Search

 
 
Thread Tools Search this Thread Display Modes
Old 12.09.2011, 10:56   #1  
propeller is offline
propeller
Участник
propeller's Avatar
 
359 / 29 (1) +++
Join Date: 25.07.2007
вопрос по Query
Простейшая задача: есть query по таблице CustTable с какими-то условиями.
Есть значение "КлиентАБВ".

Нужно проверить, есть ли запись с таким значением поля AccountNum в имеющемся query.
Понято, через queryRun.next() можно перебрать все записи и условием проверить, но хотелось бы по быстрей и покрасивей.
Old 12.09.2011, 11:09   #2  
Jorj is offline
Jorj
Участник
Jorj's Avatar
 
11 / 14 (1) ++
Join Date: 03.10.2006
Location: Киев
А что если создать копию этого query и добавить туда ренж по AccountNum, много перебирать не надо, поле уникальное – достаточно одного одного queryRun.next().
__________________
Не принимайте жизнь всерьез - это временное явление...
Old 12.09.2011, 11:11   #3  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,448 / 1792 (66) ++++++++
Join Date: 28.04.2007
Location: Калуга
В общем случае подцепить к имеющемуся query ещё один CustTable с типом связи exists join и наложить уже на него условие "КлиентАБВ". Затем, сделав один раз queryRun.next(), посмотреть вернулось ли что-нибудь.

to Jorj: если в исходном query на поле AccountNum уже есть условие, то ещё одно условие "КлиентАБВ". добавится к нему через "ИЛИ".

Ещё вариант, чтобы добится присоединения условия через "И",можно воспользоваться "расширенным синтаксисом" range (http://www.axaptapedia.com/Expressions_in_query_ranges) и добавить условие "КлиентАБВ" через какое-нибудь свободное поле (например через recid. Но и тогда в общем случае могут возникнуть проблемы совместимости, например при наличии RLS: Что делает RLS с связанными запросами в отчете).

Last edited by S.Kuskov; 12.09.2011 at 12:57.
Old 12.09.2011, 11:20   #4  
mazzy is offline
mazzy
Участник
mazzy's Avatar
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Join Date: 29.11.2001
Location: Москва
Blog Entries: 10
Quote:
Originally Posted by propeller View Post
Простейшая задача: есть query по таблице CustTable с какими-то условиями.
Есть значение "КлиентАБВ".

Нужно проверить, есть ли запись с таким значением поля AccountNum в имеющемся query.
не проверял в аксапте но примерно так:
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();
}
будут побочные эффекты, если в исходном запросе установлено больше одного критерия на поле accountNum.
__________________
полезное на axForum, github, vk, coub.
Old 12.09.2011, 11:37   #5  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,448 / 1792 (66) ++++++++
Join Date: 28.04.2007
Location: Калуга
Quote:
Originally Posted by mazzy View Post
будут побочные эффекты, если в исходном запросе установлено больше одного критерия на поле accountNum.
А если ровно один? не будут?
Вы о каких эфектах?

В случае если пользовательский фильтр по полю accountNum имеет место быть, то тогда просто взять и заменить его на "КлиентАБВ" можно только если истинно Global::inRange(Range.value, "КлиентАБВ").
В общем случае пользовательских фильтров может быть несколько, значит проверить прийдётся их все, т.е. нужен цикл. ИМХО добавить ещё одну связку по exists join будет проще.

Ещё раз. Все эти извращения нужны если "пользовательский фильтр по полю accountNum имеет место быть". Если нет, то достаточно совета Jorj и mazzy
This post has been rated by: mazzy (2).
Old 12.09.2011, 11:45   #6  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,715 / 1204 (44) ++++++++
Join Date: 13.01.2004
Blog Entries: 3
Quote:
Originally Posted by S.Kuskov View Post
В общем случае подцепить к имеющемуся query ещё один CustTable с типом связи exists join и наложить уже на него условие "КлиентАБВ". Затем сделав один раз queryRun.next() посмотреть вернулось ли что-нибудь.
К сожалению, это ничего не гарантирует. Если исходный запрос относительно сложен и имеет несколько таблиц-источников с "не линейной" схемой объединения, то подключение еще одного источника по Exists Join может привести к тому, что запросу "снесет крышу". Результат может оказаться парадоксальным.

В принципе, общая идея, заключающаяся в том, что нужно наложить еще один 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("Есть такая запись");
    }
    
}

Естесственно, этот трюк работает только для полей, которые массивами не являются. Для полей-массивов можно сделать подобное только для первого элемента массива.
This post has been rated by: coolibin (1), S.Kuskov (1), propeller (1).
Old 12.09.2011, 12:41   #7  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,448 / 1792 (66) ++++++++
Join Date: 28.04.2007
Location: Калуга
Quote:
Originally Posted by Владимир Максимов View Post
Именно для данного конкретного случая можно сделать "хитрый трюк".
Да про данный "трюк" я в курсе. Но сдаётся мне что это поведение запросто могут "исправить" в какой-нибудь следующей версии системы.

Если выбирать из предложенных вариантов, то мне больше нравится мой про использование http://www.axaptapedia.com/Expressions_in_query_ranges

P.S.: propeller, вот уж действительно "простейшая задача"

Last edited by S.Kuskov; 12.09.2011 at 13:32.
Old 12.09.2011, 13:32   #8  
mazzy is offline
mazzy
Участник
mazzy's Avatar
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Join Date: 29.11.2001
Location: Москва
Blog Entries: 10
Quote:
Originally Posted by S.Kuskov View Post
А если ровно один? не будут?
Вы о каких эфектах?
Если ровно один, то findOrCreateRange_W изменит критерий на 'КлиентАБВ' по полю.
Если меньше одного, то findOrCreateRange_W добавит критерий 'КлиентАБВ' по полю.

А вот если больше одного, то findOrCreateRange_W изменит один из критериев (первый попавшийся) на 'КлиентАБВ'. Все критерии по этому полю будут действовать через ИЛИ.

Quote:
Originally Posted by S.Kuskov View Post
В случае если пользовательский фильтр по полю accountNum имеет место быть, то тогда просто взять и заменить его на "КлиентАБВ" можно только если истинно Global::inRange(Range.value, "КлиентАБВ").
Хм...
А ведь точно.
__________________
полезное на axForum, github, vk, coub.
Old 12.09.2011, 14:31   #9  
mazzy is offline
mazzy
Участник
mazzy's Avatar
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Join Date: 29.11.2001
Location: Москва
Blog Entries: 10
мне кажется что достаточно будет добавить ",КлиентАБВ", если критерий уже существует.

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();
}
__________________
полезное на axForum, github, vk, coub.
Old 12.09.2011, 14:39   #10  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2494 (89) +++++++++
Join Date: 20.08.2005
queryRangeConcat() - это условие 'или'

Кроме того, кто может поручиться, что ранее добавленное условие - это не расширенный фильтр?
__________________
Axapta v.3.0 sp5 kr2
Old 12.09.2011, 14:48   #11  
mazzy is offline
mazzy
Участник
mazzy's Avatar
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Join Date: 29.11.2001
Location: Москва
Blog Entries: 10
ок. убедили.

вариант S.Kuskov: приджойнить exist join тоже не подойдет. поскольку в запросе уже может быть join. http://msdn.microsoft.com/en-us/libr...36(AX.10).aspx

тогда остается только перебор записей в случае, если критерий на accountNum установлен?
__________________
полезное на axForum, github, vk, coub.
Old 12.09.2011, 15:18   #12  
mazzy is offline
mazzy
Участник
mazzy's Avatar
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Join Date: 29.11.2001
Location: Москва
Blog Entries: 10
похоже вот такой способ будет работать всегда.
но если на код клиента уже был установлен критерий, то этот способ будет работать медленно.

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;
}
__________________
полезное на axForum, github, vk, coub.
Old 12.09.2011, 15:44   #13  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,448 / 1792 (66) ++++++++
Join Date: 28.04.2007
Location: Калуга
Quote:
Originally Posted by mazzy View Post
тогда остается только перебор записей в случае, если критерий на accountNum установлен?
А чем не подходит такой вариант?
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();
    }
Я вижу один недостаток - ограничение на длину строки в Range.
Old 12.09.2011, 16:06   #14  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2494 (89) +++++++++
Join Date: 20.08.2005
Quote:
Originally Posted by S.Kuskov View Post
X++:
            qbr.value(strfmt("(%1 && %2)", SuperCustRange, qbr.value()));
Хм.
А что, уже стало возможно использовать совместно расширенный синтаксис фильтров и обычный?
__________________
Axapta v.3.0 sp5 kr2
This post has been rated by: S.Kuskov (1).
Old 12.09.2011, 16:08   #15  
mazzy is offline
mazzy
Участник
mazzy's Avatar
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Join Date: 29.11.2001
Location: Москва
Blog Entries: 10
Quote:
Originally Posted by S.Kuskov View Post
Я вижу один недостаток - ограничение на длину строки в Range.
угу.
__________________
полезное на axForum, github, vk, coub.
Old 12.09.2011, 17:28   #16  
Alexius is offline
Alexius
Участник
Alexius's Avatar
 
461 / 248 (9) ++++++
Join Date: 13.12.2001
Можно попробовать добавить явный критерий по RecId искомой записи клиента, если он не используется в запросе (обычно не используется ).
Если используется, то через расширенный фильтр по аналогии с кодом клиента описанной выше у S.Kuskov.
Или напрямую распарсить критерии по RecId и либо найти в них искомый и оставить только его либо выдать облом

Last edited by Alexius; 12.09.2011 at 17:32.
Old 13.09.2011, 08:44   #17  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,448 / 1792 (66) ++++++++
Join Date: 28.04.2007
Location: Калуга
Quote:
Originally Posted by AndyD View Post
Хм.
А что, уже стало возможно использовать совместно расширенный синтаксис фильтров и обычный?
Я исходил из того что если на этом поле и есть ограничение, то оно имеет расширенный синтаксис. В общем случае, вы правы, там может оказаться и пользовательский фильтр.

Я тут ещё один чисто теоретический способ придумал .
Как понятно из обсуждения, основной проблемой является сложность присоединения, в случае уже имеющегося условия, нового контрольного условия по "И". Вот я и подумал раз уж это так проблемно, то пусть оно себе присоединяется по "ИЛИ". В результате исходный запрос изменится и это изменение можно будет анализировать. В случае если количество строк возвращаемое запросом (можно посчитать при помощи SysQuery::countTotal) станется прежним, это будет означать (конечно с определёнными ограничениями), что новое условие по ИЛИ никак не повлияло на выборку, а следовательно исходный запрос содержал в себе контрольное условие. Что и требовалость орпределить

Недостатки: на время анализа вся выборка должна быть заблокирована от корректировок для того чтобы исключить возможность изменения количества строк в запросе из вне.
Old 13.09.2011, 09:34   #18  
mazzy is offline
mazzy
Участник
mazzy's Avatar
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Join Date: 29.11.2001
Location: Москва
Blog Entries: 10
Quote:
Originally Posted by S.Kuskov View Post
а следовательно исходный запрос содержал в себе контрольное условие.
или не содержал И искомого значения в базе вообще нет.
не, не пойдет
__________________
полезное на axForum, github, vk, coub.
Old 13.09.2011, 10:37   #19  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2494 (89) +++++++++
Join Date: 20.08.2005
Quote:
Originally Posted by S.Kuskov View Post
Я исходил из того что если на этом поле и есть ограничение, то оно имеет расширенный синтаксис. В общем случае, вы правы, там может оказаться и пользовательский фильтр.
Можно на поле TableId добавлять рэйнж.
Пользователи его просто не видят в интерфейсе

Кстати, никто не обращал внимание, что критерии со статусом Hidden - не такие уж и невидимые?
Достаточно в форме расширенного фильтра вызвать расширенный фильтр (в 2009-й через комбинацию клавишь) и нажать Ok
__________________
Axapta v.3.0 sp5 kr2
Old 13.09.2011, 11:21   #20  
dn is offline
dn
Участник
Самостоятельные клиенты AX
 
486 / 159 (6) ++++++
Join Date: 26.03.2003
Location: Москва
Quote:
Originally Posted by S.Kuskov View Post
В общем случае подцепить к имеющемуся query ещё один CustTable с типом связи exists join и наложить уже на него условие "КлиентАБВ". Затем, сделав один раз queryRun.next(), посмотреть вернулось ли что-нибудь.
Quote:
Originally Posted by Владимир Максимов View Post
К сожалению, это ничего не гарантирует. Если исходный запрос относительно сложен и имеет несколько таблиц-источников с "не линейной" схемой объединения, то подключение еще одного источника по Exists Join может привести к тому, что запросу "снесет крышу". Результат может оказаться парадоксальным.
А если использовать не ExistsJoin, а InnerJoin?
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();  
}
This post has been rated by: S.Kuskov (1).
Tags
query, как правильно

 

Similar Threads
Thread Thread Starter Forum Replies Last Post
Очередной вопрос про Query rkrivov DAX: Программирование 45 16.10.2013 19:16
Вопрос по query? Hidden DAX: Программирование 1 31.07.2007 18:10
Вопрос по query и join tischenko DAX: Программирование 2 20.07.2005 13:05
Вопрос по запросу (query) Александр_1975 DAX: Программирование 2 23.01.2004 17:35
Вопрос знатокам QBE и Query в AXAPTA Maxim Gorbunov DAX: Программирование 6 27.12.2002 13:19

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Рейтинг@Mail.ru
All times are GMT +3. The time now is 10:21.
Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Contacts E-mail, Advertising.