Los FilterGroups representan uno de los mecanismos de filtrado más sofisticados y potentes en Microsoft Dynamics Business Central y Dynamics NAV, proporcionando un sistema multicapa que permite escenarios de filtrado complejos organizando los filtros en grupos separados y numerados que se combinan durante la ejecución de consultas.
Qué son los FilterGroups y su propósito en ambas plataformas
FilterGroups son contenedores lógicos que almacenan conjuntos de filtros aplicados a objetos Record o RecordRef. Cada FilterGroup se identifica mediante un número entero y contiene filtros establecidos previamente usando las funciones SETFILTER o SETRANGE.
Tipos de FilterGroups y casos de uso específicos
Número | Nombre | Propósito técnico |
-1 | Cross-column | Lógica OR: Los registros coinciden si se cumple CUALQUIER condición |
0 | Standard | Grupo predeterminado: Filtros modificables por el usuario |
1 | Global | Aplicación amplia: Filtros aplicados a toda la sesión de aplicación |
2 | Form | Filtros en página: SetTableView, SourceTableView. |
3 | Exec | Tiempo de ejecución: SubPageView, RunPageView. |
4 | Link | Relacional:DataItemLink,SubPageLink |
5 | Temp | Actualmente en desuso |
6 | Security | Permisos: Filtrado de datos basado en permisos de usuario |
7 | Factboxes | Estado UI: Gestiona estado de visualización y limpieza de factbox |
Ejemplos de uso
procedure EjemploBasicoFilterGroup()
var
Customer: Record Customer;
Text000: Label 'El filtergroup original es: %1';
Text001: Label 'El filtergroup actual es: %1';
begin
Rec.SetFilter("No.", '10000..30000');
Message(Text000, Rec.FilterGroup);
Rec.FilterGroup(100);
Rec.setrange("Location Code", 'GRIS');
Message(Text001, Rec.FilterGroup);
Rec.FilterGroup(0);
Message(Text001, Rec.FilterGroup);
end;
En este ejemplo se comprueba que por defecto se utiliza el grupo 0, luego se puede cambiar al 100 y luego otra vez al 0.
Además en los filtros del usuario se ve que únicamente puede modificar los que están en el grupo 0 pero están los del grupo 100 y no pueden eliminarse (Usualmente lo vemos en la aplicación usando el 2 y no el 100 pero puede usarse cualquier numero que no sea el 0 y es preferible evitar los que utiliza el sistema salvo necesidad de concretamente ello):

procedure CrossColumnSearchExample()
var
Customer: Record Customer;
SearchString: Text;
begin
Customer.FilterGroup(-1);
SearchString := '@*GAR*';
Customer.SetFilter(Name, SearchString);
Customer.SetFilter(contact, SearchString);
// Para visualización UI, debe usar marcado
if Customer.FindSet() then
repeat
Customer.Mark(true);
until Customer.Next() = 0;
Customer.FilterGroup(0);
Customer.MarkedOnly(true);
Page.Run(Page::"Customer List", Customer);
end;
Filtrará para que si tiene GAR en el nombre o en el contacto salga

procedure GetFiltersTest()
var
Customer: Record Customer;
OriginalGroup: Integer;
SavedFilters: Text;
begin
message(format(Rec.GetFilters())); //Nombre: *s, Filtro fecha: ''..01/01/28
Rec.FilterGroup(10);
Rec.SetFilter("No.", '10000..20000');
message(format(Rec.GetFilters())); //Nº: 10000..20000
Rec.FilterGroup(0);
message(format(Rec.GetFilters())); //Nombre: *s, Filtro fecha: ''..01/01/28
end;
Cuando utilizamos FilterGroups tenemos en contenedores distintos los filtros de forma que para consultar los filtros utilizados deberemos darnos un paseo por todos los FilterGroups activos. De esta forma en el ejemplo anterior cuando estamos en el FG10 solo vemos los filtros aplicados en el 10.
Aunque no los veamos todos están activos:

Es importante este hecho dado que si queremos saber los filtros tendremos que conocer que FilterGroups hay que:
procedure GetActiveFilterGroups()
var
ActiveGroups: List of [Integer];
i: Integer;
Filters: Text;
begin
Rec.FilterGroup(10);
Rec.SetFilter("No.", '10000..20000');
Rec.FilterGroup(8);
Rec.SetFilter("No.", '30000');
//Crear lista con los FilterGroups activos
for i := 0 to 255 do begin
Rec.FilterGroup(i);
Filters := Rec.GetFilters();
if Filters <> '' then
ActiveGroups.Add(i);
end;
message(format(ActiveGroups.Count())); //3
//Recorrer lista con FilterGroups activos
foreach i in ActiveGroups do begin
Rec.FilterGroup(i);
Filters := Rec.GetFilters();
Message('FilterGroup %1: %2', i, Filters);
//FilterGroup 0: Nombre: *s*, Filtro fecha: ''..01/01/28
//FilterGroup 8: Nº: 30000
//FilterGroup 10: Nº: 10000..20000
end;
Rec.FilterGroup(0);
end;
Otro método de filtrar la información, Mark
Si bien esto no es un FilterGroup, tiene relación con ellos por cuanto no muestran los filtros al usuario y no le dejan modificarlos.
La ventaja y desventaja de este método, con respecto al filtrado con Setrange o Setfilter, es la selección 1 a 1 de los registros a mostrar lo que hace poder establecer criterios complejos de selección, por ejemplo, filtrar los registros en los que la suma del campo importe 1 e importe 2 sea superior a 100.
Una vez establecidos para mostrar al usuario el usuario no tiene modo de ver otros registros que los seleccionados aunque dentro de ellos si podrá utilizar los filtros de usuario.
trigger OnDrillDown()
var
PurchaseHeader: Record "Purchase Header";
ComprasACR: Codeunit "Compras ACR";
PurchaseQuotes: Page "Purchase Quotes AMV";
begin
PurchaseHeader.RESET;
PurchaseHeader.FILTERGROUP(73);
PurchaseHeader.SETRANGE("Document Type", PurchaseHeader."Document Type"::Quote);
PurchaseHeader.SETRANGE("Condicion 1", FALSE);
PurchaseHeader.SETRANGE("Condicion 2", FALSE);
IF PurchaseHeader.FINDSET THEN
REPEAT
IF CumpleCondicion3(PurchaseHeader) THEN BEGIN
IF PurchaseHeader."Condicion 4" THEN
PurchaseHeader.MARK(TRUE);
END ELSE
PurchaseHeader.MARK(TRUE);
UNTIL PurchaseHeader.NEXT = 0;
//Quito los filtros porque no quiero que el usuario piense que es lo único que se aplica
PurchaseHeader.SETRANGE("Condicion 1");
PurchaseHeader.SETRANGE("Condicion 2");
PurchaseHeader.FILTERGROUP(0);
PurchaseHeader.MARKEDONLY(TRUE);
PurchaseQuotes.SETTABLEVIEW(PurchaseHeader);
PurchaseQuotes.RUN;
end;
Errores a evitar
- Evitar utilizar FilterGroups reservados. Casi en todos los sitios he encontrado el FilterGroup 2 para establecer filtros que el usuario no pueda modificar pero es un error utilizar un FilterGroup que utiliza la aplicación. Tienes hasta el 255, hay donde elegir.
- Cuantos mas FilterGroups se utilizan mas sentencias Where en SQL y menor eficiencia.
- Volver siempre al FilterGroup 0: tras aplicar filtros en otros grupos, asegúrate de devolver el contexto al grupo 0. Evitar olvidarlo reduce comportamientos inesperados en siguientes operaciones.
- Orden de aplicación de filtros: recuerda que BC combina filtros de todos los grupos activos mediante AND, salvo el -1 (Cross-column) que usa OR. Esto puede dar resultados sorprendentes si no se tienen en cuenta.
- Diferencia entre
MARK
yFILTERGROUP
en rendimiento:MARK
genera un conjunto marcado en memoria, mientras que los filtros se traducen en cláusulas SQL. En tablas grandes, los filtros suelen ser mucho más eficientes.
Conclusiones
- Los FilterGroups son una herramienta poderosa en Business Central para gestionar filtrados avanzados, combinando lógica y control sobre qué puede modificar el usuario.
- Es fundamental usar grupos personalizados y documentados, evitando los reservados por el sistema, para mantener claridad y evitar conflictos.
- Aunque permiten gran flexibilidad, un uso excesivo puede afectar al rendimiento SQL, por lo que conviene usarlos con moderación y priorizar
SETRANGE
oSETFILTER
sobreMARK
cuando sea posible. - Conocer bien cómo funcionan los FilterGroups (especialmente los especiales como
-1
y6
) permite evitar confusiones en depuración, seguridad y desarrollo de extensiones.