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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 12.09.2011, 10:56   #1  
propeller is offline
propeller
Участник
Аватар для propeller
 
359 / 29 (1) +++
Регистрация: 25.07.2007
вопрос по Query
Простейшая задача: есть query по таблице CustTable с какими-то условиями.
Есть значение "КлиентАБВ".

Нужно проверить, есть ли запись с таким значением поля AccountNum в имеющемся query.
Понято, через queryRun.next() можно перебрать все записи и условием проверить, но хотелось бы по быстрей и покрасивей.
Старый 12.09.2011, 11:09   #2  
Jorj is offline
Jorj
Участник
Аватар для Jorj
 
11 / 14 (1) ++
Регистрация: 03.10.2006
Адрес: Киев
А что если создать копию этого query и добавить туда ренж по AccountNum, много перебирать не надо, поле уникальное – достаточно одного одного queryRun.next().
__________________
Не принимайте жизнь всерьез - это временное явление...
Старый 12.09.2011, 11:11   #3  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,429 / 1772 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
В общем случае подцепить к имеющемуся 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  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от propeller Посмотреть сообщение
Простейшая задача: есть 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.
Старый 12.09.2011, 11:37   #5  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,429 / 1772 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от mazzy Посмотреть сообщение
будут побочные эффекты, если в исходном запросе установлено больше одного критерия на поле accountNum.
А если ровно один? не будут?
Вы о каких эфектах?

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

Ещё раз. Все эти извращения нужны если "пользовательский фильтр по полю accountNum имеет место быть". Если нет, то достаточно совета Jorj и mazzy
За это сообщение автора поблагодарили: mazzy (2).
Старый 12.09.2011, 11:45   #6  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,657 / 1158 (42) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
В общем случае подцепить к имеющемуся 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("Есть такая запись");
    }
    
}

Естесственно, этот трюк работает только для полей, которые массивами не являются. Для полей-массивов можно сделать подобное только для первого элемента массива.
За это сообщение автора поблагодарили: coolibin (1), S.Kuskov (1), propeller (1).
Старый 12.09.2011, 12:41   #7  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,429 / 1772 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Именно для данного конкретного случая можно сделать "хитрый трюк".
Да про данный "трюк" я в курсе. Но сдаётся мне что это поведение запросто могут "исправить" в какой-нибудь следующей версии системы.

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

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

Последний раз редактировалось S.Kuskov; 12.09.2011 в 13:32.
Старый 12.09.2011, 13:32   #8  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
А если ровно один? не будут?
Вы о каких эфектах?
Если ровно один, то findOrCreateRange_W изменит критерий на 'КлиентАБВ' по полю.
Если меньше одного, то findOrCreateRange_W добавит критерий 'КлиентАБВ' по полю.

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

Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
В случае если пользовательский фильтр по полю accountNum имеет место быть, то тогда просто взять и заменить его на "КлиентАБВ" можно только если истинно Global::inRange(Range.value, "КлиентАБВ").
Хм...
А ведь точно.
__________________
полезное на axForum, github, vk, coub.
Старый 12.09.2011, 14:31   #9  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 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.
Старый 12.09.2011, 14:39   #10  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2476 (88) +++++++++
Регистрация: 20.08.2005
queryRangeConcat() - это условие 'или'

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

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

тогда остается только перебор записей в случае, если критерий на accountNum установлен?
__________________
полезное на axForum, github, vk, coub.
Старый 12.09.2011, 15:18   #12  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 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.
Старый 12.09.2011, 15:44   #13  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,429 / 1772 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от mazzy Посмотреть сообщение
тогда остается только перебор записей в случае, если критерий на 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.
Старый 12.09.2011, 16:06   #14  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2476 (88) +++++++++
Регистрация: 20.08.2005
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
X++:
            qbr.value(strfmt("(%1 && %2)", SuperCustRange, qbr.value()));
Хм.
А что, уже стало возможно использовать совместно расширенный синтаксис фильтров и обычный?
__________________
Axapta v.3.0 sp5 kr2
За это сообщение автора поблагодарили: S.Kuskov (1).
Старый 12.09.2011, 16:08   #15  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
Я вижу один недостаток - ограничение на длину строки в Range.
угу.
__________________
полезное на axForum, github, vk, coub.
Старый 12.09.2011, 17:28   #16  
Alexius is offline
Alexius
Участник
Аватар для Alexius
 
461 / 248 (9) ++++++
Регистрация: 13.12.2001
Можно попробовать добавить явный критерий по RecId искомой записи клиента, если он не используется в запросе (обычно не используется ).
Если используется, то через расширенный фильтр по аналогии с кодом клиента описанной выше у S.Kuskov.
Или напрямую распарсить критерии по RecId и либо найти в них искомый и оставить только его либо выдать облом

Последний раз редактировалось Alexius; 12.09.2011 в 17:32.
Старый 13.09.2011, 08:44   #17  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,429 / 1772 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от AndyD Посмотреть сообщение
Хм.
А что, уже стало возможно использовать совместно расширенный синтаксис фильтров и обычный?
Я исходил из того что если на этом поле и есть ограничение, то оно имеет расширенный синтаксис. В общем случае, вы правы, там может оказаться и пользовательский фильтр.

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

Недостатки: на время анализа вся выборка должна быть заблокирована от корректировок для того чтобы исключить возможность изменения количества строк в запросе из вне.
Старый 13.09.2011, 09:34   #18  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
а следовательно исходный запрос содержал в себе контрольное условие.
или не содержал И искомого значения в базе вообще нет.
не, не пойдет
__________________
полезное на axForum, github, vk, coub.
Старый 13.09.2011, 10:37   #19  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2476 (88) +++++++++
Регистрация: 20.08.2005
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
Я исходил из того что если на этом поле и есть ограничение, то оно имеет расширенный синтаксис. В общем случае, вы правы, там может оказаться и пользовательский фильтр.
Можно на поле TableId добавлять рэйнж.
Пользователи его просто не видят в интерфейсе

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

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Очередной вопрос про 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

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

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

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 23:18.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.