• home > webfront > visualization > rudiment >

    数据可视化BI宽表到窄表转换方案探索:如AntV G2 transform.fold

    Author:zhoulujun Date:

    我们一般直接slelect * form xx_table 查询出来直接表格展示没有问题,但是希望用折线图、柱状图等图表形式展示,就需要转换。当然,我们用UNION ALL VALUES 去改变输出,但是如果纯前端呢?用图表数据集自带的transform也是方式之一


    数据库层面:什么是窄表?什么是宽表?

    在数据库中,窄表和宽表是两种设计思想,分别指的是列数少或者列数多的表格。

    • 窄表是指只包含少量列(如主键和几个属性)的表格。这种设计思想用于解决单一业务场景下的数据存储及访问问题,从而提高查询效率,减少存储空间。通常应用于 OLTP(联机事务处理)这样的在线事务处理系统。关系型数据库中大部分的表都是窄表。

      • 存储空间占用少:窄表只包含必要的字段,减少了存储空间的占用。

      • 查询效率高:窄表中字段较少,减少了表关联操作,提高了查询效率。

      • 数据结构清晰:窄表设计简洁明了,易于维护和管理。

    • 宽表则是指具有大量列的表格。这些列可以来自不同的来源,可能包括各种聚合和汇总数据等。宽表用于存储冗长的数据,以支持分析和挖掘等复杂查询,通常应用于 OLAP(联机分析处理)这样的在线分析处理系统。宽表能够提供更为全面和详细的数据,但同时也会带来一定的复杂度,包括查询效率下降等问题。

      • 减少表关联:宽表中包含了更多的冗余字段或关联字段,减少了表关联操作,提高了查询效率。

      • 数据冗余:宽表中的冗余字段可以减少查询时的数据访问次数,提高查询速度。

      • 查询性能优化:宽表可以通过预先计算复杂的数据计算结果,提高查询性能。

    e5043b37ba9a8c61a08a4a73434570b9.png

    可视化层面:什么是窄表?什么是宽表?

    宽表(wide)

    一行包含多个指标:


    catidsum_viewscount_viewsavg_views
    531148419604.4
    54010
    这个sql 常见的查询方式,比如:


    select *  from demo_table

    但是图表,无论是echarts、antV G2、D3 等,都无法直接渲染这样的数据

    窄表(long)

    每行只包含一个指标:


    catidmetricvalue
    53sum_views11484
    53count_views19
    53avg_views604.4
    54sum_views0
    图表(折线图、柱形图)多数需要这种结构。


    而这样的sql查询是时候,sql组装就复杂的的多了

    最好用的 SQL 写法(兼容 MySQL 8.0+ / PostgreSQL / ClickHouse / Doris 等现代数据库):

    SELECT 
        catid::TEXT AS catid,          -- 维度
        '求和views'    AS metric,      -- 图例名称(中文)
        SUM(views)               AS value
    FROM v9_hits 
    GROUP BY catid
    
    UNION ALL VALUES               -- MySQL 8.0+ / PostgreSQL / Doris 等支持的语法糖
        ('求和views',        SUM(views)),
        ('求和monthviews',   SUM(monthviews)),
        ('最小值views',      MIN(views)),
        ('最大值views',      MAX(views)),
        ('计数views',        COUNT(views)),
        ('去重计数views',    COUNT(DISTINCT views)),
        ('平均值views',      AVG(views)::DECIMAL(10,4))
    
    -- 如果你的数据库还不支持 VALUES 语法,就用最经典的 UNION ALL(万能版):

    万能版(所有数据库都支持):

    SELECT catid::TEXT AS catid, '求和views'    AS metric, SUM(views)              AS value FROM v9_hits GROUP BY catid
    UNION ALL
    SELECT catid::TEXT AS catid, '求和monthviews' AS metric, SUM(monthviews)          AS value FROM v9_hits GROUP BY catid
    UNION ALL
    SELECT catid::TEXT AS catid, '最小值views'    AS metric, MIN(views)              AS value FROM v9_hits GROUP BY catid
    UNION ALL
    SELECT catid::TEXT AS catid, '最大值views'    AS metric, MAX(views)              AS value FROM v9_hits GROUP BY catid
    UNION ALL
    SELECT catid::TEXT AS catid, '计数views'      AS metric, COUNT(views)           AS value FROM v9_hits GROUP BY catid
    UNION ALL
    SELECT catid::TEXT AS catid, '去重计数views'  AS metric, COUNT(DISTINCT views)  AS value FROM v9_hits GROUP BY catid
    UNION ALL
    SELECT catid::TEXT AS catid, '平均值views'    AS metric, AVG(views)             AS value FROM v9_hits GROUP BY catid
    ORDER BY catid, metric;

    返回结果就是完美长表:

    catidmetricvalue
    53求和views11484
    53平均值views604.4211
    54求和views0
    .........

    但是,如果你前端既需要展示表格视图,又需要展示图表视图,这个时候后端出两种格式太麻烦,图省事的话,就直接用图表自带的数据集方法解决,比如antV G2:https://g2.antv.antgroup.com/manual/core/data/overview

    import { Chart } from '@antv/g2';
    
    
    
    const chart = new Chart({
      container: 'container1',
      autoFit: true,
      height: 500,
    });
    
    chart.data(data);
    
    // 关键:把所有指标“长变宽” → “宽变长”,方便 G2 做多系列
    chart.scale({
      value: { nice: true },
    });
    
    chart.tooltip({
      shared: true,
      showMarkers: true,
    });
    
    chart.axis('catid', { title: { text: '栏目ID' } });
    chart.axis('value', { title: null });
    
    chart
      .line()
      .position('catid*value')
      .color('metric')           // 按指标字段区分颜色/图例
      .shape('smooth')           // 可选:平滑曲线
      .tooltip('metric*value');
    
    // 把宽表转成长表
    chart.transform({ type: 'fold', 
      fields: [
        '[求和]views',
        '[求和]monthviews',
        '[最小值]views',
        '[最大值]views',
        '[计数]views',
        '[去重计数]views',
        '[平均值]views',
      ],
      key: 'metric',    // 新字段名:指标名称
      value: 'value',   // 新字段名:指标值
      retains: ['catid'],
    });
    
    chart.legend('metric', {
      position: 'top',
    });
    
    chart.render();

    这样的坏处就是,每次修改,图表都会重新转换一遍数据

    echarts 其实更加方便,https://echarts.apache.org/handbook/zh/concepts/dataset/


    当然,你也可以不用这样考虑,就是输出为宽表,自己直接手动转换位窄表




    参考文章:
    什么是窄表?什么是宽表? https://cloud.tencent.com/developer/article/2321715



    转载本站文章《数据可视化BI宽表到窄表转换方案探索:如AntV G2 transform.fold 》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/visualization/rudiment/9712.html

    上一篇:Microsoft Fabric
    下一篇:最后一页