前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一秒钟一句话生成 PowerBI 数据字典并与同事分享

一秒钟一句话生成 PowerBI 数据字典并与同事分享

作者头像
BI佐罗
发布2022-07-07 15:36:27
2.6K0
发布2022-07-07 15:36:27
举报
文章被收录于专栏:PowerBI战友联盟PowerBI战友联盟

很多伙伴问罗叔是否可以给小白直接直接操作的技巧,例如:直接点一个按钮,直接写一个公式,直接解决一个问题的。

我是小白我怕谁

可以的。

尽管讲解一个按钮,公式,问题是很直接的。但不排除一句话可以解决大问题的神技,小白不需要理解为什么,只需要用,只需要欣赏,只需要赞叹,不仅仅帮助小白解决问题,同时让小白可以增加兴趣,来体会 Power BI 和数据分析中的美和艺术。

如何提取数据模型的信息

有很多方法提取数据模型的信息,但是对小白来说,我们需要:

一秒钟一句话生成 Power BI 数据字典并与同事分享。

这看似是一个不可能完成的任务。

的确,有很多方法和工具可以从 Power BI Desktop 的数据模型中提取信息,但是对于小白来说,怎么可以快速实现呢?

小白的标准操作在于:

第一步,复制粘贴 “度量值” 内容。

第二步,复制粘贴 “结果” 即可。

本文就是这样的案例,我们从正统的思路开始做事,让大家知道其来龙去脉,然后构建实用的解决方案,然后重构,然后优化,然后再优化,然后再反思再优化,然后再封装,然后适配小白的思想,拿来就用。

请大家一起来欣赏吧。

DAX 新函数

DAX 引擎还在进化,每一次的进化都是在主体框架下的一些小补充。但每次的小补充可能带来新的可能。今天要和大家介绍的是:

DAX 出了一个新的函数:COLUMNSTATISTICS。它可以直接返回当前数据模型中所有表和列的信息。

打开 DAX Studio,直接输入:

代码语言:javascript
复制
EVALUATE 
COLUMNSTATISTICS()

便可以得到:

分别是:

  • 表名
  • 列名
  • 最小值
  • 最大值
  • 非重复元素数
  • 最大长度(如果是文本类型)

模型数据字典

如果你正考虑输出一个模型数据字典来告知相关人员,数据模型的信息,可以快速用这个函数实现。

这样就可以获得一套当前模型中所有表和列的字典。

无法用于计算表

不难想到可以用计算表来计算以上的字典并放入当前数据模型,可惜是不行的,例如在 Power BI Desktop 中,创建计算表,并写入:

这就出现了一个循环依赖的错误。道理很简单:

正在创建的计算表也是该 DAX 函数统计的对象;而该表还没创建完;要创建该表就要计算完该 DAX 函数;而要计算完该 DAX 函数,该表就要计算完;导致循环依赖。

好可惜啊,有没有。

我们希望这个很实用的函数可以使用。

度量值实现

既然该 DAX 函数仅仅依赖表和列,但并不会依赖度量值,所以,可以通过度量值来获取信息。在写度量值前,还注意到一点,有些系统生成的表,我们并不需要,因此,可以过滤掉,写出度量值的示例,如下:

可以看出:

  • 的确可以运行成功。
  • 编辑器的智能提示出错,说明 Power BI 的公式编辑器并没有支持对该函数的解析。但的确存在该函数。

显示信息

用度量值显示一个数值不是我们想要的,毕竟我们想要的是信息,而不是有多少条数据。

根据上述实验,我们可知有这样的限制:

  • 我们想要表,但却不能用计算表;
  • 可以用度量值,但度量值却不能返回表。

这导致一个矛盾。先考虑在度量值中用字符串来实现,如下:

这的确显示了信息,但不是特别紧凑,以及有的表里面没有列,也可以不必显示,因此,可以对这个度量值再做优化,得到:

这个效果的确是我们想要的了。

其优化的度量值内容为:

代码语言:javascript
复制
Model.Info.Text = 
// 设置要排除的表,默认留空
VAR vFilterOutTables = { "" }
// 设置要排除的辅助表,如:参数,度量值容器
VAR vFilterOutTables_OneColumn = { BLANK() , "列" , "列 1" , "Value" , "Column" , "Column 1" }

// 以下内容无需修改

VAR vDictionary = 
    FILTER( COLUMNSTATISTICS() , 
        // 清除掉系统生成的内容
        NOT CONTAINSSTRING( [Table Name] , "DateTableTemplate" ) &&
        NOT CONTAINSSTRING( [Column Name] , "RowNumber" )
    )
VAR vDictionaryFiltered = FILTER( vDictionary , NOT [Table Name] IN vFilterOutTables )
VAR vTableInfoFilterd =
FILTER(
    ADDCOLUMNS(
        SUMMARIZE( vDictionaryFiltered , [Table Name] ) , 
        "@ColumnContent" , 
            CONCATENATEX( FILTER( vDictionaryFiltered ,  [Table Name] = EARLIER( [Table Name] ) ) , [Column Name] , ", " )
    ) ,
    NOT [@ColumnContent] IN vFilterOutTables_OneColumn
)
RETURN 
    CONCATENATEX( vTableInfoFilterd , 
        "表【" & [Table Name] & "】" & UNICHAR( 10 ) & "包括列:" & [@ColumnContent]
         , UNICHAR( 10 )
    )

只需要复制上述内容就可以立即提取自己的模型信息。还可以复制给工作伙伴,直接复制粘贴到微信与别人沟通。

然后粘贴到微信吧,如下:

至此,主体已经完成。已经可以拿来就用了。

但这不是我们的调性,接下来我们一起进入思想时刻。

重构

什么是” 重构” 呢?

在我们写的每篇文章以及给出的每个案例中,几乎都有 “重构” 的影子。

重构,顾名思义,就是:重新构建,说白了,就是重新做一遍。

为什么要重新做一遍呢?

重新做一遍的底层逻辑就是:超越上一个版本的自己。

因此,重构是一种重要的思想。

重构,是一种反思,它总是提醒我们进行反思,一件事情是不是可以做得更好。

大家还记得爱因斯坦用纸做小板凳的故事,做了三个版本,拿出了最好的一个。

这里的重构,除了超过上一个版本的意思,还有一层更重要的底层逻辑是:

怎么才算 “更好” 呢?

一般在我们的这个领域来形容更好,有两个方面:

  • 情感方面,你是不是有一种 “哇” 的感觉,获得了一种喜悦,超过了自己。
  • 理性方面,是不是对内容本身有意义。例如:更高更快更通用。

很明显,这两者是常常伴随而来的。

在我们的这个领域,重构,往往意味着去实现:复用,健壮性。

什么意思?

例如:对于正在看本文的小白来说,也许你对度量值一无所知,但你知道如何创建一个度量值,那么只需要复制粘贴就可以解决本文所叙述的目标下的所有问题,那么就说,这个方案是:1)通用的;2)健壮的。

下面,就让我们一起进入重构的过程,对于小白来说,可以欣赏这个过程;对于高手来说,可以参考这个过程。

第一次重构:解除名称硬编码

任何用 "" 写出的文本都存在不够通用的问题,因此,需要将硬编码的部分提取,以便未来需求变化时,在一个位置维护变化的内容。

可以对度量值再做优化,得到:

代码语言:javascript
复制
Model.Info.Text = 
// 设置要排除的表,默认留空
VAR vFilterOutTables = { "日期" , "ModelInfo" }
// 设置要排除的辅助表,如:参数,度量值容器
VAR vFilterOutTables_OneColumn = { BLANK() , "列" , "列 1" , "Value" , "Column" , "Column 1" }

// 设置表前缀等信息,默认如下,可不修改
VAR vText_Table_Prefix = "表【" // 设置表前缀
VAR vText_Table_Suffix = "】" // 设置表后缀
VAR vText_Table_IncludingColumns = "包括列:" // 设置包括列
VAR vText_Column_Splitter = ", " // 设置列分隔符

// 以下内容无需修改
VAR vDictionary = 
    FILTER( COLUMNSTATISTICS() , 
        // 清除掉系统生成的内容
        NOT CONTAINSSTRING( [Table Name] , "DateTableTemplate" ) &&
        NOT CONTAINSSTRING( [Column Name] , "RowNumber" )
    )
VAR vDictionaryFiltered = FILTER( vDictionary , NOT [Table Name] IN vFilterOutTables )
VAR vTableInfoFilterd =
FILTER(
    ADDCOLUMNS(
        SUMMARIZE( vDictionaryFiltered , [Table Name] ) , 
        "@ColumnContent" , 
            CONCATENATEX( 
                FILTER( vDictionaryFiltered ,  [Table Name] = EARLIER( [Table Name] ) ) , 
                [Column Name] , vText_Column_Splitter 
            )
    ) ,
    NOT [@ColumnContent] IN vFilterOutTables_OneColumn
)
RETURN 
    CONCATENATEX( vTableInfoFilterd , 
        vText_Table_Prefix & [Table Name] & vText_Table_Suffix & 
        UNICHAR( 10 ) & vText_Table_IncludingColumns & [@ColumnContent]
        , UNICHAR( 10 )
    )

这就完成了,效果上没有区别。

第二次重构:应对复杂工程

我们刚刚的截图非常简单,如下:

现在的问题是,如果面对的是一个大型的复杂工程,还可以吗?

第一步:先从业务逻辑上想想,有没有这个需求?

思考如下:

同事会不会问我们,数据模型中有哪些表和列的信息呢?然后要快速给出,并进行沟通。

想了一会儿,发现:的确很可能。而且还发现了另一种可能,那就是:

我们也会自己不断从数据库或文件中提取信息,但提取的信息是不是太多了,我们也不知道,尤其是表很多的时候,那么就说明这个需求是有意义的。

第二步:在实际大型工程中,试一试如下:

不难看出,非常实用,一下子就全部提取了。

一个特别实用的动作是,可以在记事本里分析和反查这些列是否合理。如下:

这可以非常快地帮助我们发现问题。

但问题来了,我们发现有的表有很多列,是否可以直观的写下有多少列呢?

因此,进行优化,效果如下:

这的确帮了大忙,我们快速地知道哪些表的列数,以便有针对性的研究下。

第三次重构:修复问题

现在就可以不断使用这个技能了。

直到发现它的问题:

只要报表界面上有任何筛选器,都会导致这个错误。仔细阅读错误信息:

COLUMNSTATISTICS () 不能与筛选上下文一起使用。

仔细思考一下原因,由于 COLUMNSTATISTICS 是用来获得模型信息的,并不是用来进行计算的,因此,DAX 引擎将其隔绝在筛选上下文之外是有道理的。

如何进行修复呢?

既然错误是:不能与筛选上下文一起使用。那么可以清除掉所有的筛选上下文即可。

最后得到了带有这种保护的版本。如下:

代码语言:javascript
复制
Model.Info.Text = 

// 进行设置:

    // 设置要排除的表,默认留空
    VAR vFilterOutTables = { "" } // 如果要排除某表,如日期表,可以将表名放入。
    // 设置要排除的辅助表,如:参数,度量值容器
    VAR vFilterOutTables_OneColumn = { BLANK() , "列" , "列 1" , "Value" , "Column" , "Column 1" , "Column1" }

    // 设置表前缀等信息,默认如下,可不修改
    VAR vText_Table_Prefix = "表【" // 设置表前缀
    VAR vText_Table_Suffix = "】" // 设置表后缀
    VAR vText_Table_IncludingColumns = "包括列:" // 设置包括列
    VAR vText_Table_IncludingColumns_Prefix = "(共 " // 设置 共 x 列
    VAR vText_Table_IncludingColumns_Suffix = " )" // 设置 共 x 列

    VAR vText_Column_Splitter = ", " // 设置列分隔符

// 以下内容无需修改

RETURN

CALCULATE(
    
    VAR vDictionary = 
        FILTER( COLUMNSTATISTICS() , 
            // 清除掉系统生成的内容
            NOT CONTAINSSTRING( [Table Name] , "DateTableTemplate" ) && //系统的日期表
            NOT CONTAINSSTRING( [Table Name] , "LocalDateTable" ) && //表列对应的日期表列
            NOT CONTAINSSTRING( [Column Name] , "RowNumber" ) // 系统生成的表索引
        )
    VAR vDictionaryFiltered = FILTER( vDictionary , NOT [Table Name] IN vFilterOutTables )
    VAR vTableInfoFilterd =
    FILTER(
        ADDCOLUMNS(
            SUMMARIZE( vDictionaryFiltered , [Table Name] ) , 
            "@ColumnCount" , COUNTROWS( FILTER( vDictionaryFiltered ,  [Table Name] = EARLIER( [Table Name] ) ) ) ,
            "@ColumnContent" , 
                CONCATENATEX( 
                    FILTER( vDictionaryFiltered ,  [Table Name] = EARLIER( [Table Name] ) ) , 
                    [Column Name] , vText_Column_Splitter 
                )
        ) ,
        NOT [@ColumnContent] IN vFilterOutTables_OneColumn
    )
    RETURN
        CONCATENATEX( vTableInfoFilterd , 
            vText_Table_Prefix & [Table Name] & vText_Table_Suffix & 
            vText_Table_IncludingColumns_Prefix  & [@ColumnCount] & vText_Table_IncludingColumns_Suffix &
            
            UNICHAR( 10 ) & vText_Table_IncludingColumns & [@ColumnContent]
            , UNICHAR( 10 )
        )
    // 清除筛选上下文
    , REMOVEFILTERS( )

)

// by BI佐罗

用 CALCULATE 配合 REMOVEFILTERS 来保护 COLUMNSTATISTICS 的执行。

于是,此时就得到了一个无懈可击的重构版本,它具备这样的特点:

  • 可以直接复制粘贴使用,无任何依赖。
  • 可以设置各种配置。
  • 针对问题给出保护,没有了复杂度。

小白时刻

作为小白,如果你整个文章都没有读懂,完全没有关系,只需要看以下三句话即可。

要获得数据模型的数据字典信息并与同事分享交流,只需要两步:

第一步,新建度量值,复制粘贴上述 “Model.Info.Text” 内容。

第二步,拖入 Power BI Desktop 报表,复制后去微信粘贴即可。

高手时刻

如果你正在学习 DAX,那你可以看到 DAX 的一个综合运用了,可以体会其中每一步的 DAX 用法。

如果你可以正确地 Thinking In Table,那么用 DAX 就可以帮助我们构建灵巧的解决方案。

总结

快去复制粘贴到你的项目中试试吧。

扩展思考

在此强调,如果仅仅是为了解决一个目标:快速提取数据模型的信息,那仅仅复制粘贴以上度量值即可。

但这里怀着再进一步重构的想法,我们观察到:

在整套解决方案的逻辑链条中,有这样的前提假设:

  • 我们想要表,但 COLUMNSTATISTICS 却不能用于计算表;
  • 可以用度量值,但度量值却不能返回表。

再加上:

  • 一个度量值提取信息的先入为主的设计初衷。

导致:

我们得到了现在的解决方案。

但是,

如果我们真的想得到一个表怎么办呢?

当我们第一次这样尝试的时候,会触发一个错误:

不能与筛选上下文一起使用。

但是,我们已经发现了这个问题的弥补方法,那就是:用 CALCULATE 配合 REMOVEFILTERS 来保护 COLUMNSTATISTICS 的执行。

既然如此,我们思考:

是不是可以构建一套表格方式的解决方案呢?

也就是:

这个问题就留给大家思考吧。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PowerBI战友联盟 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 我是小白我怕谁
  • 如何提取数据模型的信息
  • DAX 新函数
  • 模型数据字典
  • 无法用于计算表
  • 度量值实现
  • 显示信息
  • 重构
  • 第一次重构:解除名称硬编码
  • 第二次重构:应对复杂工程
  • 第三次重构:修复问题
  • 小白时刻
  • 高手时刻
  • 总结
  • 扩展思考
相关产品与服务
腾讯云 BI
腾讯云 BI(Business Intelligence,BI)提供从数据源接入、数据建模到数据可视化分析全流程的BI能力,帮助经营者快速获取决策数据依据。系统采用敏捷自助式设计,使用者仅需通过简单拖拽即可完成原本复杂的报表开发过程,并支持报表的分享、推送等企业协作场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档