热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PowerBI:NATURALINNERJOIN的使用

查看官方的文档,NATURALINNERJOIN描述是这样的:语法NATURALINNERJOIN(,)参

查看官方的文档,NATURALINNERJOIN描述是这样的:

语法

NATURALINNERJOIN(, )

参数



术语

定义

LeftTable

用于定义联接左侧的表的表表达式。

RightTable

用于定义联接右侧的表的表表达式。



返回值

一个表,仅包含两个表的指定共有列都存在值的行。 返回的表将具有左侧表的公用列以及这两个表中的其他列。

备注


  • 这些表在两个表的共有列(按名称)上联接。 如果两个表没有公共列名,则返回错误。


  • 结果没有排序顺序保证。


  • 两个表中要联接的列必须具有相同的数据类型。


  • 只能基于同一源表中的列(具有相同的世系)进行联接。 例如,对于 Products[ProductID]、WebSales[ProductdID] 和 StoreSales[ProductdID],WebSales 和 StoreSales 表与 Products 表之间存在基于 ProductID 列的多对一关系,因而 WebSales 和 StoreSales 表基于 [ProductID] 进行联接。


  • 联接期间使用严格的比较语义。 类型强制转换不适用;例如 1 不等于 1.0。


  • 在已计算的列或行级安全性 (RLS) 规则中使用时,不支持在 DirectQuery 模式下使用此函数。

总结了一下,NATURALINNERJOIN主要运用在两个场景:

  1. 用于有关系的表

这个好理解,只需要将LeftTable、RightTable两个参数替换成已经建立关联关系的表名即可。

  1. 用于无关系的表

借助DAX圣经里面的例子:

EVALUATE
VAR A =
UNION (
ROW ( "Name", "Audio", "Value", 1 ),
ROW ( "Name", "Audio", "Value", 2 ),
ROW ( "Name", "Computers", "Value", 3 ),
ROW ( "Name", "Games", "Value", 4 ),
ROW ( "Name", "Music", "Value", 5 )
)
VAR B =
UNION (
ROW ( "Name", "Audio", "Ext", 6 ),
ROW ( "Name", "Computers", "Ext", 7 ),
ROW ( "Name", "Computers", "Ext", 8 ),
ROW ( "Name", "Games", "Ext", 9 ),
ROW ( "Name", "TV", "Ext", 10 )
)
RETURN
NATURALINNERJOIN ( A, B )

在DAX Studio执行后得到的结果为:







圣经中还提到:

用于无关系表的注意事项:

NATURALINNERJOIN 通常用于无关系的两个表,在这种情况下函数遵循以下规则:

  • 结果不保证排序顺序。


  • 两表用于连接的公共列必须使用相同的名称,且具有相同的数据类型。


  • 连接使用的列必须具有相同的数据沿袭,或者都不具备数据沿袭。


  • 连接使用严格的比较语义。不会强制转换类型,例如,1 不等于 1.0。

用于关系表的注意事项:

NATURALINNERJOIN 可以用于存在关系的两个表,在这种情况下,通过 Power BI Desktop 新建表和在 DAX Studio 中创建查询的行为有所不同:

  • 在 Power BI Desktop 中使用此函数新建表,两表不能包含同名列,否则将报错。


  • 在 DAX Studio 中创建的查询不受同名列的限制,结果可以区分来自不同表的相同列。

圣经源地址:https://www.powerbigeek.com/understanding-naturalinnerjoin/

遇到的问题

在实际运用中,两个无关系的表在使用NATURALINNERJOIN往往出现各种问题,以下是我的问题分析过程:

已知两个表:factCostControl,factCosBreakdown

它们都有字段CostKey,且都是字符型,并已经建立了1对多的关联关系。

在某一个计算中需要使用到这两个表的数据,如果只是简单的检索他们的交集,写法很简单:

EVALUATE
NATURALINNERJOIN(
    ALL('factCosBreakdown'),
ALL('factCostControl')
)

或者:

EVALUATE
NATURALINNERJOIN(
'factCosBreakdown',
'factCostControl'
)

以上两个公式,在没有任何外部筛选器的情况下,它们得到的结果是相同的,会检索出两个表相互交叉的所有数据。

而由于这两个表本身都有几十个字段,当我在使用ALL函数时,这两个表的几十个字段都参与计算,结果就导致性能很差,于是改进了写法:

EVALUATE
NATURALINNERJOIN(
ALL(
'factCosBreakdown'[CostKey],
'factCosBreakdown'[MainProjectID],
'factCosBreakdown'[ReportMonth],
'factCosBreakdown'[CostType],
'factCosBreakdown'[AllocationProjectID],
'factCosBreakdown'[AllocationTypeID]
),
ALL(
'factCostControl'[CostKey],
'factCostControl'[IsPair],
'factCostControl'[ReportControlCentreNo]
)
)

上面的写法中,我只提取了需要用到的字段,并用ALL将它们包起来,ALL会去掉作用在这个表上的所有筛选器,按文章开头说法,这样写应该是没问题的,它们都有一个同名同数据类型的字段CostKey,但在DAX Studio运行时却报错:

未检测到公用联接列。联接函数“NATURALINNERJOIN”至少需要一个公用联接列。

于是想到,虽然factCosBreakdown和factCostControl已经建立了关联关系,但是这种写法可能导致它们的关系已经失效,它们现在就相当于两个无关联关系的表,于是尝试改进写法:

EVALUATE
NATURALINNERJOIN(
SELECTCOLUMNS(
ALL(
'factCosBreakdown'[CostKey],
'factCosBreakdown'[MainProjectID],
'factCosBreakdown'[ReportMonth],
'factCosBreakdown'[CostType],
'factCosBreakdown'[AllocationProjectID],
'factCosBreakdown'[AllocationTypeID]
),
"CostKey",[CostKey],
"MainProjectID",[MainProjectID],
"ReportMonth",[ReportMonth],
"CostType",'factCosBreakdown'[CostType],
"AllocationProjectID",[AllocationProjectID],
"AllocationTypeID",[AllocationTypeID]
),
SELECTCOLUMNS(
ALL(
'factCostControl'[CostKey],
'factCostControl'[IsPair],
'factCostControl'[ReportControlCentreNo]
),
"CostKey",[CostKey],
"IsPair",[IsPair],
"ReportControlCentreNo",[ReportControlCentreNo]
)
)

使用SELECTCOLUMNS函数将需要的字段都提取出来,还是报错:

检测到不兼容的联接列(''[CostKey])。'NATURALINNERJOIN' 不支持使用具有不同的数据类型或世系的联接。

这个提示很明白,说CostKey字段数据类型不一致,但是在Power BI Desktop中查看,CostKey确实都是文本类型,想不明白,直接给它们强制转换:

EVALUATE
NATURALINNERJOIN(
SELECTCOLUMNS(
ALL(
'factCosBreakdown'[CostKey],
'factCosBreakdown'[MainProjectID],
'factCosBreakdown'[ReportMonth],
'factCosBreakdown'[CostType],
'factCosBreakdown'[AllocationProjectID],
'factCosBreakdown'[AllocationTypeID]
),
"CostKey",CONVERT([CostKey],STRING),
"MainProjectID",[MainProjectID],
"ReportMonth",[ReportMonth],
"CostType",'factCosBreakdown'[CostType],
"AllocationProjectID",[AllocationProjectID],
"AllocationTypeID",[AllocationTypeID]
),
SELECTCOLUMNS(
ALL(
'factCostControl'[CostKey],
'factCostControl'[IsPair],
'factCostControl'[ReportControlCentreNo]
),
"CostKey",CONVERT([CostKey],STRING),
"IsPair",[IsPair],
"ReportControlCentreNo",[ReportControlCentreNo]
)
)

问题终于解决。

总结:

在两个无关系的表之间使用NATURALINNERJOIN时,可以通过强制转换它们的同名列数据类型以达到数据兼容的目的。



推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 这篇文章主要介绍了Python拼接字符串的七种方式,包括使用%、format()、join()、f-string等方法。每种方法都有其特点和限制,通过本文的介绍可以帮助读者更好地理解和运用字符串拼接的技巧。 ... [详细]
  • 如何优化Webpack打包后的代码分割
    本文介绍了如何通过优化Webpack的代码分割来减小打包后的文件大小。主要包括拆分业务逻辑代码和引入第三方包的代码、配置Webpack插件、异步代码的处理、代码分割重命名、配置vendors和cacheGroups等方面的内容。通过合理配置和优化,可以有效减小打包后的文件大小,提高应用的加载速度。 ... [详细]
  • 本文整理了Java中org.apache.hadoop.hive.ql.plan.ExprNodeColumnDesc.getTypeInfo()方法的一些代码示例,展 ... [详细]
  • 基于分布式锁的防止重复请求解决方案
    一、前言关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求。而这样的重复请求如果是幂等的(每次请求的结果都相同,如查 ... [详细]
author-avatar
c肀xc86_441
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有