Цитата:
Сообщение от
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;
}