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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 12.10.2009, 20:23   #1  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Group by и временная таблица
AX 4.0 SP2

Тестируя отчёт, случайно поймал глюк:
X++:
static void job(Args _args)
{
    tmpTable tmpTable;
    counter cnt;
    ;

    tmpTable.clear();
    tmpTable.Field1 = '1';
    tmpTable.insert();

    tmpTable.clear();
    tmpTable.Field1 = '1';
    tmpTable.insert(); // вставляем две одинаковые строки

    cnt = 0;
    while select tmpTable
    group by Field1
//    where tmpTable.Field1 == '1'
    {
        cnt++;
    }

    info(int2str(cnt));
}
Если раскомментировать предложение WHERE то цикл выполнится 2 раза! У кого-нибудь воспроизводится?

P.S.: Обязательные условия: таблица - временная; поле - текстовое
За это сообщение автора поблагодарили: miklenew (3).
Старый 12.10.2009, 20:36   #2  
Varmen is offline
Varmen
Участник
 
190 / 13 (1) ++
Регистрация: 02.10.2007
а это не потому что,
select TmpTable = select * from TmpTable, т.е со всей тучей полей типа RecId itd?

Группировка соответсвенно тут не помогает.


Т.е нужно явно написать

X++:
select Field1 from tmpTable
group by Field1
__________________
The Variable men power.

Последний раз редактировалось Varmen; 12.10.2009 в 20:44.
Старый 12.10.2009, 20:47   #3  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Не помогает . И к тому же без where - работает корректно!
Старый 12.10.2009, 21:21   #4  
ZVV is offline
ZVV
MCITP
MCP
Oracle
MCBMSS
 
1,006 / 246 (11) ++++++
Регистрация: 13.02.2004
Адрес: Минск
->
Цитата:
Сообщение от Varmen Посмотреть сообщение
а это не потому что,
select TmpTable = select * from TmpTable, т.е со всей тучей полей типа RecId itd?

Группировка соответсвенно тут не помогает.


Т.е нужно явно написать

X++:
select Field1 from tmpTable
group by Field1
Нужели вы каждый раз так пишете при группировке?
Аксапта сама этот момент "распознаёт", так что явно писать вовсе не обязательно.
__________________
Zhirenkov Vitaly
Старый 12.10.2009, 21:57   #5  
Varmen is offline
Varmen
Участник
 
190 / 13 (1) ++
Регистрация: 02.10.2007
ага, особенно когда join , не раз палился. при поиске ошибки, лучше явно поставить, дабы исключить разную трактовку ситуации.
__________________
The Variable men power.

Последний раз редактировалось Varmen; 12.10.2009 в 22:02.
Старый 12.10.2009, 22:06   #6  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от Varmen Посмотреть сообщение
ага, особенно когда join , не раз палился. при поиске ошибки, лучше явно поставить, дабы исключить разную трактовку ситуации.
А пример можете привести, когда явное указания выбираемых полей, участвующих в группировке, хоть как-то влияет на результат?

Цитата:
Сообщение от ZVV Посмотреть сообщение
Аксапта сама этот момент "распознаёт", так что явно писать вовсе не обязательно.
+1
Старый 12.10.2009, 22:28   #7  
Varmen is offline
Varmen
Участник
 
190 / 13 (1) ++
Регистрация: 02.10.2007
не, не смогу такое привести.
Но ведь Вы мною предложенный вариант попробовали правда? Знаете почему, потому что jobik не работает так как изначально задумали, а причина неизвестна.
__________________
The Variable men power.
Старый 12.10.2009, 22:55   #8  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
не работает "как задумали" - мягко сказано

Если фильтровать текстовое поле, участвующее в группировке, то group by попросту игнорируется! (причём, например, для целочисленного поля тот же код отрабатывает корректно )

Что я делаю не так?
Кто-нибудь может прокомментрировать такое поведение group by? Это следствие каких-то известных (документированных) ограничений?
И какие ещё сюрпризы от использования временных таблиц можно ожидать?
Старый 14.10.2009, 10:08   #9  
Bishop is offline
Bishop
Участник
 
89 / 60 (3) ++++
Регистрация: 12.08.2004
Адрес: Москва
А кто-нибудь встречал в стандарте запросы с group by без использования аггрегирующих функций? (не только для временных таблиц, но и для обычных)
Я лично не сталкивался, и всегда думал, что если используешь group by, то добавь хотя бы count(RecId)...
Старый 14.10.2009, 10:19   #10  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
Цитата:
Сообщение от Bishop Посмотреть сообщение
А кто-нибудь встречал в стандарте запросы с group by без использования аггрегирующих функций? (не только для временных таблиц, но и для обычных)
Я лично не сталкивался, и всегда думал, что если используешь group by, то добавь хотя бы count(RecId)...
Ну вообще много где так делается (пример SalesFromLetter::CheckParmTable(), SalesFormLetter_PackingSlip.writeJournalSalesLink() и т.д.)
и я при group by никогда не использую аггрегирующие функции, так как group by сам по себе предполагает вывод только тех полей, которые указаны в нем.
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
За это сообщение автора поблагодарили: Bishop (1).
Старый 14.10.2009, 12:50   #11  
Bishop is offline
Bishop
Участник
 
89 / 60 (3) ++++
Регистрация: 12.08.2004
Адрес: Москва
Цитата:
Сообщение от lev Посмотреть сообщение
Ну вообще много где так делается (пример SalesFromLetter::CheckParmTable(), SalesFormLetter_PackingSlip.writeJournalSalesLink() и т.д.)
и я при group by никогда не использую аггрегирующие функции, так как group by сам по себе предполагает вывод только тех полей, которые указаны в нем.
SalesFromLetter::checkParmTable()
X++:
        while select salesParmT
                group by CustAccount
                where salesParmT.ParmId == parmId
        {
            numOfAccounts += 1;
        }
От подобного кода на слое sys становится немного грустно...
Старый 14.10.2009, 12:54   #12  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от Bishop Посмотреть сообщение
От подобного кода на слое sys становится немного грустно...
А как бы вы сделали?
Старый 15.10.2009, 12:40   #13  
Bishop is offline
Bishop
Участник
 
89 / 60 (3) ++++
Регистрация: 12.08.2004
Адрес: Москва
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
Цитата:
Сообщение от Bishop
От подобного кода на слое sys становится немного грустно...
А как бы вы сделали?
Это была риторическая грусть
Для достижения distinct я пользуюсь двумя глобальными статическими методами:
1) notexists join на эту же таблицу - позволяет получить кол-во различных значений по группе полей, так же работает со временными таблицами, неприменим для таблиц с большим количеством строк (если не использовать доп. критерии), так как запрос вызывает на sql-сервере сущий ад...
X++:
// Возвращает кол-во различных значений заданного набора полей таблицы
// Формируется запрос:
#if.never
    select count(RecId) from table
        where
            table.FieldRange1   == value1       &&  // доп. условия
            ...
    notexists join tableNE                          // tableNE.TableId = table.TableId
        where
            tableNE.RecId       <  table.RecId  &&  // основная идея
            tableNE.Field1      == table.Field1 &&  // набор полей
            ...                                 &&
            tableNE.FieldRange1 == value1       &&  // доп. условия
            ...
#endif
static counter distinctValues(
    TableId     _tableId,               // код таблицы
    container   _conFields,             // перечень полей
    container   _conRanges  = connull(),// перечень критериев [fieldId, range, ...]
    Common      _tmpCommon  = null      // временная таблица
    )
{
    DictTable               dictTable;
    Common                  common;
    Common                  commonNE;
    Query                   query;
    QueryBuildDataSource    qbds, qbdsNE;
    QueryRun                queryRun;
    int                     i;
    ;
    query = new Query();
    qbds = query.addDataSource(_tableId, "ds1");
    qbds.orderMode(OrderMode::GroupBy);
    qbds.addSelectionField(fieldNum(Common, RecId), SelectionField::Count);
    for (i = 1; i <= conlen(_conRanges) div 2; i+=2)
    {
        qbds.addRange(conpeek(_conRanges, i)).value(conpeek(_conRanges, i+1));
    }
    qbdsNE = qbds.addDataSource(_tableId, "ds2");
    qbdsNE.joinMode(JoinMode::NoExistsJoin);
    qbdsNE.addRange(fieldNum(Common, RecId)).value("((ds2.RecId < ds1.RecId))");
    for (i = 1; i <= conlen(_conFields); i++)
    {
        qbdsNE.addLink(conpeek(_conFields, i), conpeek(_conFields, i));
    }
    for (i = 1; i <= conlen(_conRanges) div 2; i+=2)
    {
        qbdsNE.addRange(conpeek(_conRanges, i)).value(conpeek(_conRanges, i+1));
    }
    queryRun = new QueryRun(query);
    if (_tmpCommon)
    {
        dictTable   = new DictTable(_tableId);
        common      = dictTable.makeRecord();
        commonNE    = dictTable.makeRecord();
        common.setTmpData(_tmpCommon);
        commonNE.setTmpData(_tmpCommon);
        queryRun.setCursor(common, 1);
        queryRun.setCursor(commonNE, 2);
    }
    queryRun.next();
    return queryRun.getNo(1).RecId;
}
2) Прямой запрос на sql-сервер. Не работает со временными таблицами и ограничивает получение различных значений только по одному полю
X++:
// Возвращает кол-во различных значений заданного поля таблицы
/* Выполняется sql-запрос:
SELECT COUNT (DISTINCT Field) FROM Table WHERE ...
*/
server static counter distinctValuesDirect(
    TableId     _tableId,               // код таблицы
    FieldId     _fieldId,               // код поля
    container   _conRanges = connull()  // перечень критериев [fieldId, range, ...]
    )
{
    DictTable       dictTable = new DictTable(_tableId);
    ResultSet       resultSet;
    SqlSystem       sqlSystem = new SqlSystem();
    str             sql;
    str             rangeList;
    int             i;
    ;
    if (dictTable.dataPrCompany())
    {
        rangeList = strfmt(" where %1 = %2",
            dictTable.fieldName(fieldNum(Common, DataAreaId), DbBackend::Sql),
            sqlSystem.sqlLiteral(curext()) );
    }
    for (i = 1; i <= conlen(_conRanges) div 2; i+=2)
    {
        rangeList = (rangeList ? "" : " where ") + rangeList + (rangeList ? " and " : "") +
            strfmt("%1 = %2",
                dictTable.fieldName(conpeek(_conRanges, i), DbBackend::Sql),
                sqlSystem.sqlLiteral(conpeek(_conRanges, i+1)) );
    }
    sql = strfmt("select count (distinct %1) from %2%3",
        dictTable.fieldName(_fieldId, DbBackend::Sql),
        dictTable.name(DbBackend::Sql),
        rangeList);
    new SqlStatementExecutePermission(sql).assert();
    resultSet = new Connection().createStatement().executeQuery(sql);
    CodeAccessPermission::revertAssert();
    if (resultSet.next())
    {
        return resultSet.getInt64(1);
    }
    return 0;
}
За это сообщение автора поблагодарили: sukhanchik (1), S.Kuskov (1).
Старый 14.10.2009, 13:16   #14  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,326 / 3556 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от Bishop Посмотреть сообщение
От подобного кода на слое sys становится немного грустно...
Ну.. не боги горшки обжигают... даже у буржуев. С одной стороны. А с другой стороны - альтернатива данному коду - есть только через exists join со справочником, что требует дополнительного мыслительного процесса - что за справочник и как он связан.
__________________
Возможно сделать все. Вопрос времени
Старый 14.10.2009, 13:40   #15  
ZVV is offline
ZVV
MCITP
MCP
Oracle
MCBMSS
 
1,006 / 246 (11) ++++++
Регистрация: 13.02.2004
Адрес: Минск
->
Цитата:
Сообщение от Bishop Посмотреть сообщение
SalesFromLetter::checkParmTable()
X++:
        while select salesParmT
                group by CustAccount
                where salesParmT.ParmId == parmId
        {
            numOfAccounts += 1;
        }
От подобного кода на слое sys становится немного грустно...
Ну альтернативы то:
либо то что тут,
либо как сказали выше (и на ссылке выше тоже есть пример), делать экзист со справочником...
Тоже не шибко всё красиво...
__________________
Zhirenkov Vitaly
Старый 14.10.2009, 10:28   #16  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
В связи с отсутствием distinct, использование group by без аггрегирующих функций не такая уж и редкость в Axapta
Старый 26.10.2009, 15:49   #17  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
AX 4.0 SP2

Тестируя отчёт, случайно поймал глюк:
X++:
static void job(Args _args)
{
    tmpTable tmpTable;
    counter cnt;
    ;

    tmpTable.clear();
    tmpTable.Field1 = '1';
    tmpTable.insert();

    tmpTable.clear();
    tmpTable.Field1 = '1';
    tmpTable.insert(); // вставляем две одинаковые строки

    cnt = 0;
    while select tmpTable
    group by Field1
//    where tmpTable.Field1 == '1'
    {
        cnt++;
    }

    info(int2str(cnt));
}
Если раскомментировать предложение WHERE то цикл выполнится 2 раза! У кого-нибудь воспроизводится?

P.S.: Обязательные условия: таблица - временная; поле - текстовое
В АХ 6, похоже, уже это починили.
Старый 14.07.2011, 20:37   #18  
Maximin is offline
Maximin
NavAx
NavAx Club
 
412 / 346 (12) ++++++
Регистрация: 09.10.2002
Адрес: Москва
На 2009 RU6 починили... RU5 не пробовал...
__________________
Жизнь прекрасна! Если, конечно, правильно подобрать антидепрессанты...
Старый 16.01.2015, 10:25   #19  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от kashperuk Посмотреть сообщение
В АХ 6, похоже, уже это починили.
Цитата:
Сообщение от Maximin Посмотреть сообщение
На 2009 RU6 починили... RU5 не пробовал...
А как вы проверяли?
Я на AX2009 RU7 сейчас опять наступил на эти грабли. Проверил на AX2012R3 - грабли все ещё там!

Вот видоизменил тестовый джоб, чтобы не нужно было создавать таблицу вручную (используется таблица существующую в стандартном приложении ).
X++:
static void Job_test20150116(Args _args)
{
    TmpABC TmpABC;
    counter cnt;
    ;

    TmpABC.clear();
    TmpABC.ItemId = '1';
    TmpABC.RefRecId = 0;
    TmpABC.doinsert();

    TmpABC.clear();
    TmpABC.ItemId = '1';
    TmpABC.RefRecId = 1;
    TmpABC.doinsert(); // вставляем две одинаковые строки

    cnt = 0;
    while select TmpABC
    group by ItemId
    where TmpABC.ItemId == '1' // !!! с этим условием группировка не выполняется
    {
        info(TmpABC.ItemId); 
        cnt++;
    }

    info(strfmt("Количество итераций цикла: %1", cnt));
}
Теги
bug, баг, временная таблица, запрос (query), ошибка

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Временная таблица Antoncheg DAX: Программирование 21 15.08.2008 18:25
производительность: map или временная таблица kitty DAX: Программирование 5 15.11.2007 12:36
Временная таблица + RLS leshy DAX: Программирование 6 27.04.2006 12:39
select sum(amount) from временная таблица ATimTim DAX: Программирование 6 11.06.2004 14:16
next и временная таблица Dron AKA andy DAX: Программирование 3 24.04.2003 16:42

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

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

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 01:02.