Dynamics 365 Business Central: How to find the last second record in the table via AL (Four ways)

Dynamics 365 Business Central

Hi, Readers.
Today I would like to discuss an interesting question that was asked recently, how to find last second record in the table via AL.

For example, how to get the record of customer 40000 in the customer table below. Regardless of the purpose, is there a convenient way to do this?

In this post, I will simply share three methods, hoping to help those who need this.
PS: Dynamics 365 Business Central: How to get the sort order for the records returned (Record.GetAscending Method)

1. Using Repeat-until (Loop)

This way of thinking is very simple. First, sort the data in the order you need, such as in descending order, and then find the second value, which is the second to last.
This only loops once, so it shouldn’t have much of an impact on performance.

Test code:

pageextension 50119 CustomerListExt extends "Customer List"
{
    actions
    {
        addafter("Co&mments")
        {
            action(GetLastSecondRecord)
            {
                Caption = 'Get Last Second Record';
                ApplicationArea = All;
                Promoted = true;
                PromotedCategory = Process;
                Image = GetLines;

                trigger OnAction()
                var
                    Cust: Record Customer;
                    i: Integer;
                begin
                    i := 0;
                    Cust.Reset();
                    Cust.Ascending(false);
                    if Cust.FindSet() then
                        repeat
                            i := i + 1;
                            if i = 2 then begin
                                Message('The second to last Customer Name: %1', Cust.Name);
                                exit;
                            end;
                        until Cust.Next() = 0;
                end;
            }
        }
    }
}

PS: This can also be done using Cust.Next(-1), the challenge is to reduce the number of loops.

pageextension 50119 CustomerListExt extends "Customer List"
{
    actions
    {
        addafter("Co&mments")
        {
            action(GetLastSecondRecord)
            {
                Caption = 'Get Last Second Record';
                ApplicationArea = All;
                Promoted = true;
                PromotedCategory = Process;
                Image = GetLines;
                trigger OnAction()
                var
                    Cust: Record Customer;
                    i: Integer;
                begin
                    i := 0;
                    Cust.Reset();
                    if Cust.FindLast() then
                        repeat
                            i := i + 1;
                            if i = 2 then
                                Message('The second to last Customer Name: %1', Cust.Name);
                        until (Cust.Next(-1) = 0) or (i = 2);
                end;
            }
        }
    }
}

2. Using Record.FindLast() Method twice

Record.FindLast() Method: Finds the last record in a table based on the current key and filter.
This method is also very interesting. We can first find the last value, then exclude it in the filter, and then find the last value again, which is the second to last value.

Very simple.

Test code:

pageextension 50119 CustomerListExt extends "Customer List"
{
    actions
    {
        addafter("Co&mments")
        {
            action(GetLastSecondRecord)
            {
                Caption = 'Get Last Second Record';
                ApplicationArea = All;
                Promoted = true;
                PromotedCategory = Process;
                Image = GetLines;

                trigger OnAction()
                var
                    Cust: Record Customer;
                    Cust1: Record Customer;
                begin
                    Cust.Reset();
                    Cust.Ascending(true);
                    if Cust.FindLast() then begin
                        Cust1.Reset();
                        Cust1.SetFilter("No.", '<>%1', Cust."No.");
                        if Cust1.FindLast() then
                            Message('The second to last Customer Name: %1', Cust1.Name);
                    end;
                end;
            }
        }
    }
}

3. Using Record.FindLast() Method and Record.Next([Integer]) Method

This method comes from the community, thanks for the information. It is similar to the second method, but it is a little more concise.

Test code:

pageextension 50119 CustomerListExt extends "Customer List"
{
    actions
    {
        addafter("Co&mments")
        {
            action(GetLastSecondRecord)
            {
                Caption = 'Get Last Second Record';
                ApplicationArea = All;
                Promoted = true;
                PromotedCategory = Process;
                Image = GetLines;
                trigger OnAction()
                var
                    Cust: Record Customer;
                begin
                    Cust.Reset();
                    Cust.Ascending(true);
                    if Cust.FindLast() and (Cust.Next(-1) = -1) then
                        Message('Customer Name: %1', Cust.Name);
                end;
            }
        }
    }
}

4. Using Query Object (Query.TopNumberOfRows Method)

As you might know, in SQL Statement, we can use SQL SELECT TOP Clause to specify the number of records to return.
The SELECT TOP clause is useful on large tables with thousands of records. Returning a large number of records can impact performance. For example, SELECT TOP 3 * FROM Customer

So if you use SQL statements this time, you can do it with the following statements.

SELECT TOP 1 * From
(select Top 2 * from Customer ORDER BY CustomerNo DESC) x                     
ORDER BY CustomerNo

But unfortunately, there is no such convenient method in AL. If we want to do something similar, we can use Query Object. Because we can use Query.TopNumberOfRows([Integer]) Method.

Query.TopNumberOfRows([Integer]) Method: Specifies the maximum number of rows to include in the resulting data set of a query.

Let’s look at a simple example. First we need to create a Query Object, sets the results to include the top 2 the results in descending order

Then get the second value from the created Query Object. Because the Query Object does not have a FindLast method, a simple loop is required.

Same result: Test video

Test code:

pageextension 50119 CustomerListExt extends "Customer List"
{
    actions
    {
        addafter("Co&mments")
        {
            action(GetLastSecondRecord)
            {
                Caption = 'Get Last Second Record';
                ApplicationArea = All;
                Promoted = true;
                PromotedCategory = Process;
                Image = GetLines;

                trigger OnAction()
                var
                    GetLastSecondCustomer: Query "Get Last Second Customer";
                    i: Integer;
                begin
                    i := 0;
                    if GetLastSecondCustomer.Open() then
                        while GetLastSecondCustomer.Read() do begin
                            i := i + 1;
                            if i = 2 then
                                Message('The second to last Customer Name: %1', GetLastSecondCustomer.Customer_Name);
                        end;
                    GetLastSecondCustomer.Close();
                end;
            }
        }
    }
}

query 50123 "Get Last Second Customer"
{
    // Sets the results to include the top 2 the results in descending order
    TopNumberOfRows = 2;
    OrderBy = descending(Customer_Number);

    elements
    {
        dataitem(C; Customer)
        {
            column(Customer_Number; "No.")
            {
            }

            column(Customer_Name; Name)
            {
            }
        }
    }
}

Great, give it a try!!!😁

END

Hope this will help.

Thanks for reading.

ZHU

コメント

Copied title and URL