FilterGroup(-1), cross-column search in Business Central and Navision.
We all know how to work with FilterGroup method in development, but sometimes we forget about specific -1 FilterGroup, which is powerfull tool for filtering. Let's figure out what it is and learn how to work with it using examples.
From the Microsoft documentation, we see only a short description of FilterGroup (-1):
Used to support the cross-column search.
This is not enough to understand how it works. But, for our luck we can find example from documentation.
var
SearchString: Text;
begin
Customer.FilterGroup := -1;
SearchString := '@*John*';
Customer.SetFilter(Customer.Name, SearchString);
Customer.SetFilter(Customer.Contact, SearchString);
end;
This makes it more obvious how it works. Usually, we use AND statement for filtering, but in this case it is OR. It is important to remember that, operations with tables are sent to the SQL server in SQL syntax. So let's write pseudo-SQL code for our case, it will look like this:
SELECT *
FROM Customer
WHERE (Name like @'John') OR
(Contact like @'John')
Let's replace Customer.FilterGroup(-1) to default Customer.FilterGroup(0)
SELECT *
FROM Customer
WHERE (Name like @'John') AND
(Contact like @'John')
Important: using * and forcing a case insensitive search (@) will effectively turn of indexing, this can negatively affect performance for large tables.
Let's imagine that we need to find all records that contain specific data in any of the fields. In our specific example, let's look for the word 'export' inside any fields in table Customer:
procedure CrossColumnSearchCustomers()
var
RecRef: RecordRef;
FieldRefVar: FieldRef;
Counter: Integer;
FilterTxt: Text;
begin
FilterTxt := '@*export*';
RecRef.Open(Database::Customer);
RecRef.FilterGroup(-1);
FOR Counter := 1 TO RecRef.FieldCount() DO BEGIN
FieldRefVar := RecRef.FieldIndex(Counter);
if FieldRefVar.Class() <> FieldClass::FlowFilter then
if (FieldRefVar.Type() in [FieldType::Code, FieldType::Text])
and (FieldRefVar.Length() >= StrLen(FilterTxt)) then begin
if FieldRefVar.Class() = FieldClass::FlowField then
FieldRefVar.CalcField();
FieldRefVar.SETFILTER(FilterTxt);
end;
end;
if RecRef.FindSet() then
repeat
Message(RecRef.GetPosition());
until RecRef.Next() = 0;
RecRef.Close();
end;
This code will find all records in the same way as Search on list pages, but for all text and code fields (page search only for page fields).
Let's say we have a set of Sales Line records from the entire base, and we need to exclude one specific record from the set. The easiest and fastest way to do this is to use FilterGroup (-1). Here is partial list of Sales Lines from my DB, let's say I want to exclude Sales Line from red box:
procedure ExcludeEntryFromSalesLine()
var
SalesLine: Record "Sales Line";
begin
//Full set of records, count is 33
message(Format(SalesLine.Count()));
SalesLine.FilterGroup(-1);
SalesLine.SetFilter("Document Type", '<>%1', SalesLine."Document Type"::Invoice);
SalesLine.SetFilter("Document No.", '<>%1', '103205');
SalesLine.SetFilter("Line No.", '<>%1', 20000);
//Set of records exlude one specific entry, count is 32
message(Format(SalesLine.Count()));
end;
Important: Cross-column search does not work on UI side, it means, if you want to show filtered data on a page, you must do it in different way, for example, filter with FilterGroup(-1) and mark the records which you want to show.
As you can see from the examples, we must not forget about the power of FilterGroup (-1), it is a powerful filtering tool that can solve many complex problems. My examples are just some of the possible uses of this group, this is just the tip of the iceberg.