Показать сообщение отдельно
Старый 15.10.2009, 12:40   #28  
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).