Цитата:
Сообщение от
Dron AKA andy
... После непродолжительных размышлений над оригинальным кодом я заметил некую странность: мы сначала наполняем контейнер названиями полей в SQL-интерпретации через
X++:
dictTable.fieldName(this.field(i), DbBackend::SQL)
, а затем повторно получаем названия тех же полей, но уже чуть видоизмененным способом:
X++:
dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy)
Буду рад, если кто-нибудь мне объяснит, почему сделано именно так ...
Для
MS SQL Server разницы в вызове
dictTable.fieldName(...) c параметром
fieldNameGenerationMode по-умолчанию или со значением
fieldNameGenerationMode::FieldListGroupBy нет никакой(по крайней мере я ее не замечал), а вот для
Oracle разница существенная.
В случае, наличия в индексе строкового поля, при вызове
dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy) ядро AX преобразует поля к одному регистру, добавляя вызов
substr и
nls_lower.
Т.е. в
AX 3.0 для СУБД
Oracle вызов
dictTable.fieldName(this.field(i), DbBackend::SQL) для строкового поля вернет
field, а вызов
dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy) - вернет
substr(nls_lower(field), 1, strlen(field)).
В конфигурации АОСа
AX4.0 есть параметр -
Database Tuning\AutoGeneration Options\Include SUBSTR and LOWER in all SELECT statements to support Oracle mixed-case systems, который видимо и отвечает за генерацию данного
substr и
nls_lower.
В итоге, если в таблице есть значения строкового поля
'SSS' и
'sss', данное поле включено в индекс и используемая СУБД
Oracle, то замена
X++:
dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy)
на
X++:
dictTable.fieldName(this.field(i), DbBackend::SQL)
приведет к тому, что при использовании пункта
'Дубликаты' - появится инфолог -
'Дубликатов нет'. А при попытке сделать индекс уникальным, вывалится ошибка, о не возможности его создания, поскольку ядро AX при создании индекса на
Oracle использует все те же
substr и
nls_lower
В связи с этим, привожу немного измененный код(для
AX 3.0, аналогичные изменения можно внести и для
AX 4.0), который одинаково работает как на SQL, так и на Oracle.
X++:
void showDuplicates()
{
tableId tableId = this.tableid();
DictTable dictTable = new DictTable(tableId);
boolean dataPrCompany = dictTable.dataPrCompany();
container fields;
Counter numberOfFields = this.numberOfFields();
Counter i;
str stmtStr;
str resultLineStr;
str resultField;
str resultField1;
UserConnection con = new UserConnection();
Statement stmt = con.createStatement();
ResultSet resultSet;
boolean anyDuplicates = false;
;
if (dataPrCompany)
fields += dictTable.fieldname(fieldnum(common,DataAreaId),DbBackend::SQL);
for (i = 1; i <= numberOfFields; i++)
{
fields += dictTable.fieldName(this.field(i), DbBackend::SQL);
}
//srf -->
//if (dataPrCompany)
// numberOfFields++;
//srf <--
stmtStr = 'select count(*)';
//srf -->
if (dataPrCompany)
{
stmtStr += ', ' + dictTable.fieldName(fieldnum(Common,DataAreaId),DbBackend::Sql,0,FieldNameGenerationMode::FieldListGroupBy);
}
//srf <--
for (i = 1; i <= numberOfFields; i++)
{
stmtStr += ', ' + dictTable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::FieldListGroupBy);
}
stmtStr += ' from ' + dictTable.name(DbBackend::SQL);
stmtStr += ' group by ';
//srf -->
if (dataPrCompany)
{
stmtStr += dictTable.fieldName(fieldnum(Common,DataAreaId),DbBackend::Sql,0,FieldNameGenerationMode::FieldListGroupBy);
if (numberOfFields >= 1)
{
stmtStr+= ', ';
}
}
//srf <--
for (i = 1; i <= numberOfFields; i++)
{
if (i > 1)
stmtStr += ', ';
stmtStr += dicttable.fieldName(this.field(i),dbBackend::Sql,0,fieldNameGenerationMode::GroupByFieldList);
}
//srf -->
if (dataPrCompany)
numberOfFields++;
//srf <--
stmtStr += ' having count(*) > 1';
if (numberOfFields > 0)
{
stmtStr += ' order by ';
for (i = 1; i <= numberOfFields; i++)
{
if (i > 1)
stmtStr += ', ';
stmtStr += int2str(i+1);
}
stmtStr += ' desc';
}
resultSet = stmt.executeQuery(stmtStr);
while (resultSet.next())
{
resultLineStr = "@SYS283" + strFmt(': %1', resultSet.getString(1));
for (i = 1; i <= numberOfFields; i++)
{
resultField = strLtrim(resultSet.getString(i+1));
if (i == 1 && dataPrCompany)
resultField1 = resultField;
else
resultLineStr += strFmt(', %1: \'%2\'', conPeek(fields, i), resultField);
}
if (dataPrCompany)
setPrefix(strFmt('%1: %2', conPeek(fields, 1), resultField1));
info(resultLineStr);
anyDuplicates = true;
}
if (!anyDuplicates)
info("@SYS68671");
}
P.S. Кстати данную функцию починили в
AX2009, а параметр
Database Tuning\AutoGeneration Options\Include SUBSTR and LOWER in all SELECT statements to support Oracle mixed-case systems в конфигурации АОСа отсутсвует.