单元格过滤数据集

概述

在使用SQL类型的数据集,定义具体SQL时,可以在SQL中通过表达式引用具体的单元格,以实现利用单元格数据过滤数据集中数据的功能。 比如下面的例子: ./asserts/20220921114148.png] 上面的例子中,第一、二列,为branch数据集中的两个字段;第三、四列为dept数据集的两个字段;第五、六列为employee数据集的两个字段。这其中branch数据集获取的是所有数据,而dept和employee数据集则是利用在SQL中依赖单元格名称实现数据集的过滤功能,从页实现我们现在看到的三层数据的分组显示功能,下面我们就来具体看下这个功能是如何使用的。

定义SQL数据集

branch数据集

先来看看branch数据集的定义,截图如下:

20220921114832.png 可以看到,branch数据集就是获取branch表中所有数据,不对数据进行过滤处理。

dept数据集

dept数据集定义截图如下:

20220921115022.png

dept数据集对应的SQL为:

select * from dept where branch_id=${A2}

在这个SQL当中,我们添加了一个条件branch_id=${A2},就是将branch_id的值限制为A2单元格的值,我们知道,在BaskReport当中,SQL中使用表达式需要放在${}符号中,所以上面的A2就表示取A2单元格的值。 数据集在定义的时候实际上不会依赖于任何单元格,所以必须要将dept数据集中对应的字段绑定到具体的单元格,那么dept数据集SQL中对应的条件要获取A2单元格的值才可行。所以我们在预览这个数据集的数据时,会看到返回的是一个空的列表。

employee数据集

与dept数据集定义方式类似,截图如下: 20220921115639.png 在employee数据集中,SQL中添加的条件是dept_id=${C2},同样就表示其字段在绑定具体单元格时,将依据当前单元格所在位置取C2单元格的值来作为dept_id字段的过滤条件值。

设计报表

设计好的报表模版如下图所示:

20220921115922.png 可以看到,在A2单元格绑定的是branch数据集的branch_id字段,C2单元格绑定的是dept数据集的dept_id字段;这样,在处理C2单元格时因为还未加载过dept数据集,所以会尝试加载这个数据集中的数据,但在加载dept数据集中数据时,对应的SQL要求取A2单元格的值作为branch_id字段的过滤条件(branch_id=${A2}),C2单元格会根据自己所在位置取到的A2单元格的值,就是branch数据集下branch_id字段展开后的值,所以可以实现根据A2单元格的值来过滤C2单元格的值。

同样E2单元格绑定的是employee数据集的employee_id字段,employee数据集中的SQL要获取C2单元格的值来作为入参过滤数据,同样又因为C2单元格绑定的是dept数据集的dept_id字段,所以通过E2单元格就可以取到相对于E2单元格的C2单元格值作为employee数据集中的SQL的入参条件值。

保存预览,就可以看到之前截图后的效果。

数据重新加载数据的原则

上面的例子中,D2单元格绑定的是dept数据集的dept_name字段,它的左父格是C2,所以D2会在C2计算完成后再计算,又因为D2单元格和C2单元格绑定的数据集相同,所以D2单元格会直接从其左父格C2单元格中获取dept数据集的dept_name字段的值,而不会重新计算dept数据集的值来填充D2单元格。同理,对于F2单元格也是这样。

对于SQL类型的数据集依赖单元格值为条件过滤数据的情况,要求这种数据集的字段必须要与单元格绑定,运行时会根据绑定单元格的父格关系来查找SQL中引用的目标单元格的值,如果找不到目标单元格,那么就会产生单元格找不到的错误。

适用场景

这种关联具体单元格的SQL数据集适合于主从结构的报表,特别是从表的数据量特别大的情况。对于从表数据量特别大的情况如果采用本章中介绍的表达式过滤数据集过滤之类的方法实现,那么首先可能会占用大量的内存,因为这些方法都需要将从表数据全部加载到内存,再根据报表单元格中配置的条件过滤数据,另一方面可能会导致性能问题,因为过滤时中需要迭代从表中所有数据。

凡事有利必有弊,这种在数据集SQL中关联单元格实现数据过滤的方式,将数据过滤的工作交给数据库去完成,会产生大量的查询,以本小节中的三级主从表为例,最终查询数据库的次数由C2和E2单元格的数量决定,所以上面的示例中,数据库的查询总次数=branch数据集一次+C2单元格的数量+E2单元格的数量

综上,在这种SQL中关联单元格实现从表数据过滤报表中,SQL中的条件部分对应的字段最好是建好相关索引,以防止多次查询对数据库的压力过大。

在Bean数据集中使用单元格参数

在BaskReport报表当中,除了可以在SQL数据集中使用单元格为入参外,在Bean数据集中也可以使用单元格参数,先来看看Bean数据集在定义的时候需要实现的四个方法:

    /**
     * @param context 上下文对象,从中可以获取报表参数,和需要的单元格值
     * @return 返回数据集数据
     */
    public abstract List<?> getData(BeanContext context);

    /**
     * @return 返回当前数据集在计算时需要依赖的单元格名称,如果不依赖单元格返回null或空的List
     */
    public abstract List<String> getDependCells();

    /**
     * @return 返回当前数据集名称,不能返回空
     */
    protected abstract String name();

    /**
     * @return 返回当前数据集对应的字段集合,不能为空
     */
    public abstract List<Field> getFields();

这其中的第二方法getDependCells,就是要求我们在实现Bean数据集时指定依赖的单元格列表,当然如果没有依赖的单元格返回null或一个空的List就可以。

一旦我们在getDependCells方法中返回了需要依赖的单元格名称后,那么在运行获取数据的getData(BeanContext context)方法中,通过参数context中的getCellValue(String cellName)就可以取到对应的单元格的值,比如我们下面的一个实现:

    @Override
    public List<?> getData(BeanContext context) {
        Object a1=context.getCellValue("A1");
        Object b1=context.getCellValue("B1");
        System.out.println("A1:"+a1);
        System.out.println("B1:"+b1);
        List<Map<String,Object>> datas=new ArrayList<Map<String,Object>>();
        //...
        return datas;
    }

    @Override
    public List<String> getDependCells() {
        List<String> list=new ArrayList<String>();
        list.add("A1");
        list.add("B1");
        return list;
    }

上面的实现中,我们在getDependCells()方法中返回A1和B1单元格,所以在getData方法中就可以通过context的getCellValue方法获取A1和B1单元格的值,当然是否能获取到对应单元格的值,还取决于当前数据集字段绑定的具体单元格位置,原理和上面介绍的SQL数据集原理相同,这里不再赘述。

results matching ""

    No results matching ""