Showing posts with label Query Range. Show all posts
Showing posts with label Query Range. Show all posts

2016-11-02

[AX2009] Merge Query Range from Two Different Queries

In my case, I want to merge query ranges from Query object to Form Data source. The data source will join to CustTable. The CustTable will be filtered by Query Object TIDCustTable.

public class FormRun extends ObjectRun
{
    QueryBuildDatasource    qbds3;
    Query                   q3;
    QueryRun                qRunCustTable;
}
 public void init()
{
    QueryBuildDatasource    qbds1, qbds4;
    ;
    qRunCustTable = new QueryRun(QueryStr(TIDCustTable));
    super();
    qbds1 = TIDIRTable_ds.query().dataSourceTable(tablenum(TIDIRTable));
    qbds4 = SalesTableDS_ds.query().dataSourceTable(tablenum(SalesTable));
    qbds4.addLink(fieldnum(TIDIRTable, SalesId), fieldnum(SalesTable, SalesId));

    qbds3 = qbds1.addDataSource(tablenum(CustTable));
    qbds3.addLink(fieldnum(TIDIRTable, InvoiceAccount), fieldnum(CustTable, AccountNum));

}

When click Select button:
void btnSelect()
{
    ;
    if(qRunCustTable.prompt())
    {
        q3  = new Query(qRunCustTable.query());
    }
}
Process button:
public void btnProcess()
{
    QueryBuildDatasource    qbds1 = TIDIRTable_ds.query().dataSourceTable(tablenum(TIDIRTable));
    QueryBuildDatasource    qbds4 = SalesTableDS_ds.query().dataSourceTable(tablenum(SalesTable));
    ;

    if(element.validateProcess())
    {
        qbds3.clearRanges();
        if(qRunCustTable.query().dataSourceTable(tablenum(CustTable)).rangeCount() >0)
            element.mergeRanges(TIDIRTable_ds.query(), qRunCustTable.query(), 4);//4 is table number of CustTable in TIDIRTable query


        SysQuery::findOrCreateRange(qbds1, fieldnum(TIDIRTable, InvoiceDate)).value(SysQuery::range(dtFromDate.dateValue(), dtToDate.dateValue()));
        if(txBranch.valueStr())
        {
            SysQuery::findOrCreateRange(qbds1, fieldnum(TIDIRTable, CountryRegionId)).value(SysQuery::value(txCountryRegionId.valueStr()));
            SysQuery::findOrCreateRange(qbds1, fieldnum(TIDIRTable, Branch)).value(SysQuery::value(txBranch.valueStr()));
        }
        else
        {
            if(qbds1.findRange(fieldnum(TIDIRTable, CountryRegionId)))
                qbds1.clearRange(fieldnum(TIDIRTable, CountryRegionId));

            if(qbds1.findRange(fieldnum(TIDIRTable, Branch)))
                qbds1.clearRange(fieldnum(TIDIRTable, Branch));
        }

        if(cbSalesStatus.selection() == SalesStatus::None)
        {
            qbds4.joinMode(JoinMode::OuterJoin);
            if(qbds4.findRange(fieldnum(SalesTable, SalesStatus)))
            {
                qbds4.clearRange(fieldnum(SalesTable, SalesStatus));
            }
        }
        else
        {
            qbds4.joinMode(JoinMode::InnerJoin);
            SysQuery::findOrCreateRange(qbds4, fieldnum(SalesTable, SalesStatus)).value(SysQuery::value(cbSalesStatus.selection()));
        }
        TIDIRTable_ds.executeQuery();
    }
}

Merge method:
public void mergeRanges(Query       q,
                               Query       initQ,
                               int         dsNo,
                               int         initQdsNo = 1,
                               boolean     alwaysAddDatasource     = false,
                               boolean     addSameFieldRange       = true)
{
    QueryBuildRange     fromQbr;
    QueryBuildRange     toQbr;
    QueryBuildDynalink  dyna;
    Counter             fromI = 1;
    //int                 qdsNo = initQdsNo;
    int                 qdsNo = dsNo;
    Counter             toI;
    tableId             tableId;
    DictField           dictField;
    int                 dictIndex;
    int                 originalId;

    void add()
    {
        q.addDataSource(initQ.dataSourceNo(initQdsNo).file());
        qdsNo = q.dataSourceCount();
    }

    void findToQbr(fieldId id)
    {
        originalId  = id;
        id          = fieldExt2Id(id);
        toQbr       = null;

        // get table id & dictField
        tableId = q.dataSourceNo(qdsNo).table();
        dictField = new DictField(tableId,id);
        dictIndex = originalId >> 16;

        // If this is a dimension field, get range using the array index, otherwise get range with id
        if ( ((dictField.arraySize() > 1) && q.dataSourceNo(qdsNo).findRange(fieldId2Ext(id, dictIndex))) ||
            ((dictField.arraySize() <= 1) && q.dataSourceNo(qdsNo).findRange(id)) )
        {
            // If same range is found, then next range
            if (! addSameFieldRange)
                continue;

            toI = 1;
            while (toI)
            {
                // is this a Dimension field?
                if (dictField.arraySize() > 1)
                    toQbr  = q.dataSourceNo(qdsNo).findRange(fieldId2Ext(id, dictIndex),toI);
                else
                    toQbr  = q.dataSourceNo(qdsNo).findRange(id,toI);

                if (! toQbr)
                    break;

                // If To value is empty, use it later
                if (! toQbr.value())
                    break;

                // If To and From values are equal then add new range later
                if (toQbr.value() == fromQbr.value())
                    break;

                toI++;
            }
        }
        if (! toQbr             ||
            (addSameFieldRange  &&
             toQbr              &&
             toQbr.value()      &&
             fromQbr.value()    &&
             toQbr.value()      != fromQbr.value()
            )
           )
        {

            if (dictField.arraySize() > 1)
            {
                // yes, working with Dimension
                toQbr  = q.dataSourceNo(qdsNo).addRange(fieldId2Ext(id, dictIndex));
            }
            else
            {
                toQbr  = q.dataSourceNo(qdsNo).addRange(id);
            }
        }
    }


    // Start

    if (! initQ)
        throw error(strfmt("@SYS23669",funcname()));

    if (! initQ.dataSourceNo(initQdsNo))
        throw error(strfmt("@SYS23667",funcname()));

    if (! q)
        throw error(strfmt("@SYS23669",funcname()));
/*
    if (q.dataSourceCount() >= initQdsNo)
    {
        if (q.dataSourceNo(initQdsNo).file() != initQ.dataSourceNo(initQdsNo).file())
        {
            if (alwaysAddDatasource)
                add();
            else
               throw error(strfmt("@SYS23668",funcname()));
        }
    }
    else
        add();
*/
    if (! initQ)
        return;

    for (fromI=1;fromI<=initQ.dataSourceNo(initQdsNo).rangeCount();fromI++)
    {
        fromQbr = initQ.dataSourceNo(initQdsNo).range(fromI);

        findToQbr(fromQbr.field());

        if (toQbr)
        {
            // Only set if From has a value
            if (fromQbr.value())
                toQbr.value(fromQbr.value());

            switch (fromQbr.status())
            {
                case RangeStatus::Locked:
                    if (toQbr.status() == RangeStatus::Open)
                        toQbr.status(RangeStatus::Locked);
                    break;
                case RangeStatus::Hidden:
                    switch (toQbr.status())
                    {
                        case RangeStatus::Open,RangeStatus::Locked:
                            toQbr.status(RangeStatus::Hidden);
                            break;
                    }
                    break;
            }
        }

    }

    fromI = 1;
    while (fromI <= initQ.dataSourceNo(initQdsNo).dynalinkCount())
    {
        dyna =  initQ.dataSourceNo(initQdsNo).dynalink(fromI);

        findToQbr(dyna.field());

        if (toQbr)
            toQbr.value(queryValue(dyna.cursor().(dyna.dynamicField())));

        fromI++;
    }
}

2011-07-27

Ekspresi Dalam Query Range

Untuk memodifikasi atau membentuk range yang agak spesifik dibutuhkan syntax yang khusus. Di bawah merupakan salah satu contoh untuk memberikan filter antara dua field dalam satu tabel dimana salah satu data dalam field yang berbeda memenuhi syarat maka akan ditampilkan dalam dialog info.
Field apa saja dapat digunakan sebagai field range. Yang terpenting adalah ekspresi dari query range tersebut. Untuk membentuk suatu ekspresi harus memenuhi persyaratan:

  • Expresi harus dibuka dan ditutup dengan menggunakan single-quotes( ' ).
  • Semua ekspresi dan sub ekspresi harus dibuka dan ditutup dengan buka dan tutup kurung.
  • Kalau hanya menggunakan satu table, nama tabel tidak perlu di sebutkan, cukup dengan nama field.
  • Untuk tabel harus menggunakan nama datasource, bukan nama table.
  • Nilai String, bisa menggunakan string biasa dan diberi double-quotes ("), atau menggunakan queryValue().
  • Untuk nilai Base Enum, berikan nilai integernya dengan fungsi any2int() atau enum2int().
  • Untuk nilai tanggal harus menggunakan fungsi Date2StrXpp().
  • Gunakan valueEmptyString pada class SysQuery (SysQuery::valueEmptyString())

static void myExperiment(Args _args)
{
    CustInvoiceJour         custInvoiceJour;
    Query                   q;
    QueryBuildDataSource    qbds;
    QueryBuildRange         qRange;
    QueryRun                qr;
    TransDate               invDate, dueDate;
    str                     rangeValue;
    ;
    invDate = 011\2011;
    dueDate = 033\2011;

    q = new Query();
    qbds = q.addDataSource(tablenum(CustInvoiceJour));
    qRange = qbds.addRange(fieldnum(CustInvoiceJour, InvoiceId));

    rangeValue = '((%1.%2==%3) || (%1.%4==%5))';
    rangeValue = strfmt(rangeValue,
            qbds.name(),
            fieldstr(CustInvoiceJour, InvoiceDate) , Date2StrXpp(invDate),
            fieldstr(CustInvoiceJour, DueDate), Date2StrXpp(dueDate)
    );

    qRange.value(rangeValue);

    qr = new QueryRun(q);
    while(qr.next())
    {
        custInvoiceJour = qr.get(tablenum(CustInvoiceJour));
        info(strfmt("%1 - %2 - %3", custInvoiceJour.InvoiceId, custInvoiceJour.InvoiceDate, custInvoiceJour.DueDate));
    }
}

Sumber: Axaptapedia, Developing for Dynamics AX: Using Expressions in Query Ranges