
应用背景
数据的本质是为了业务服务,从而达到更高效的工作方式,实现数据对业务的赋能和推动作用。
因此在构建报表时,需要开发者有设计思维
,能够考虑多种应用场景,帮助业务解决实际应用中的问题。
例如,在实际业务场景中,管理层用户习惯向下管理的方式,那么在查看报表时,能否也保留这种方式呢?
规则描述
-
组织架构分为多级,1级、2级、3级,数字越小,级别越高
-
上级用户有权限查看下属子部门数据
-
各级用户在查看报表时,默认展开下级部门,例如1级部门用户,则展示下属所有2级部门,以此类推
-
当用户分管多个平级部门时,则展示自身所在层级,不进行展开
案例数据


图1和图2两张事实表分别存储Actual和Budget数据。
-
预算和实际存在挂在
父级部门不下放
的情况,因此事实表存在1级2级3级部门混合在一列的情况 -
除了预算和实际存在此情况外,有时候
项目
也会存在这种情况

图3是维度表,存储部门数据。
-
因为存在预算和实际不下放的情况,所以需要将本部门下落到子级,保证该部门的数据完整
-
除了保证数据完整,还要保证数据可进行钻取,父级部门既可以看到下属子级部门的数据,也可以看到挂靠在本部门的数据

图4是维度表,存储Actual和Budget的类别数据。

级别 | 字段1 | 字段2 | 字段3 |
---|---|---|---|
1 | 一级 | 一级 | 一级 |
1 | 一级 | 二级 | 二级 |
1 | 一级 | 二级 | 三级 |
2 | 一级 | 一级 | 一级 |
2 | 二级 | 二级 | 二级 |
2 | 二级 | 三级 | 三级 |
3 | 一级 | 一级 | 一级 |
3 | 二级 | 二级 | 二级 |
3 | 三级 | 三级 | 三级 |
图5是多维的维度表,本身是部门维度数据的变体。
-
多维表结构图,是多维表的设计理念
-
级别分为3级,代表着部门的层级结构
-
从权限管理的角度来说,子级部门不可以看到归属上级部门的数据
-
每个级别中,都有不属于该级别的数据,例如:2级部门中,存在1级部门,这个是为了保证测试时,每个级别的数据都是完整的,减少测试的工作量

图6是配置表,存储用户的权限信息。

图7是表模型,多维表和配置表不需要建立模型关系。
构建度量值
01.Actual =
SUM ( 'Fact_Act'[实际] )
02.Budget =
SUM ( 'Fact_Bud'[预算] )
03.AnalysisActual =
VAR Analysis=
VALUES ('Dim_Analysis'[L3])
VAR Result=
CALCULATE ([01.Actual], FILTER ('Dim_Dept','Dim_Dept'[部门2] IN Analysis))
RETURN
Result
04.AnalysisBudget =
VAR Analysis=
VALUES ('Dim_Analysis'[L3])
VAR Result=
CALCULATE ([02.Budget], FILTER ('Dim_Dept','Dim_Dept'[部门2] IN Analysis))
RETURN
Result
05.AnalysisRate =
DIVIDE ( [03.AnalysisActual], [04.AnalysisBudget] )
可视化结果

添加轴权限
06.DisplayLevel =
VAR Access =
CALCULATE (
MIN ( 'Config_Access'[ID_DepartmentLevel] ),
'Config_Access'[LB_AdAccount] = USERNAME ()
) + 0
VAR AccessCount =
COUNTROWS (
CALCULATETABLE (
VALUES ( 'Config_Access'[LB_Accessible] ),
'Config_Access'[LB_AdAccount] = USERNAME (),
'Config_Access'[ID_DepartmentLevel] = Access
)
)
VAR AccessLevel =
IF ( AccessCount > 1 && Access <> 0, Access - 1, Access )
VAR Result =
IF (
AccessLevel <> 3,
VALUE ( MIN ( 'Dim_Analysis'[LB_LEVEL] ) ) - AccessLevel,
VALUE ( MIN ( 'Dim_Analysis'[LB_LEVEL] ) ) - 2
)
RETURN
Result
DAX解析
-
变量Access是为了获取当前用户的
最大权限
,数字越小权限越大 -
如果用户有访问此报表的权限,但是权限表中没有对应的权限数据,则该用户为Admin权限,Access度量值需
要进行补0
操作 -
变量AccessCount是为了获取当前用户的权限行数,因为存在一个
用户管理多个部门
的情况 -
变量AccessLevel是为了输出参数,实际场景中,如果用户管理多个部门,全部展开下属部门数据会变的特别多,因此不需要展开,仅需要展示同级即可
-
变量Result是
判断用户默认的查看层级
,如果用户非3级部门,那么管理多个部门看本级,管理一个部门看子级,3级部门则看本级
结果

从结果上看,权限控制展示的维度是正确的,但是展示的数据不正确,A的达成率应该是16.67%,C的达成率应该是2.33%。
产生原因
-
筛选器会将X轴的所有字段与列图例里面的字段组合,重新构建上下文
-
筛选器构建上下文的过程中,度量值03参与了此过程,导致一部分值被排除在外了
-
类别维度表与部门维度表之间没有直接关系,二者在一起有类似笛卡尔积的效果,也对结果有影响
解决方案
度量值内部权限判断,不依赖于筛选器判断
07.DisplayRate =
VAR Access=
CALCULATE (
MIN ('Config_Access'[ID_DepartmentLevel]),
'Config_Access'[LB_AdAccount]= USERNAME ()
)+0
VAR AccessCount=
COUNTROWS (
CALCULATETABLE (
VALUES ('Config_Access'[LB_Accessible]),
'Config_Access'[LB_AdAccount]= USERNAME (),
'Config_Access'[ID_DepartmentLevel]=Access
)
)
VAR AccessLevel=
IF (AccessCount>1&&Access<>0,Access-1,Access)
VAR Result=
IF (
AccessLevel<>3,
VALUE ( MIN ('Dim_Analysis'[LB_LEVEL]))-AccessLevel,
VALUE ( MIN ('Dim_Analysis'[LB_LEVEL]))-2
)
RETURN
IF (Result=1,[05.AnalysisRate], BLANK () )
结果如下:

度量值内部屏蔽多余上下文干扰
08.AnalysisRateExcept =
CALCULATE (
DIVIDE ( [03.AnalysisActual], [04.AnalysisBudget] ),
ALLEXCEPT ( 'Dim_Analysis', 'Dim_Analysis'[L1] ),
ALL ( 'Dim_Type'[类别] )
)
结果如下:

计算组封装,屏蔽干扰因素
VAR Access =
CALCULATE (
MIN ('Config_Access'[ID_DepartmentLevel]),
'Config_Access'[LB_AdAccount]= USERNAME ()
)+0
VAR AccessCount=
COUNTROWS (
CALCULATETABLE (
VALUES ('Config_Access'[LB_Accessible]),
'Config_Access'[LB_AdAccount]= USERNAME (),
'Config_Access'[ID_DepartmentLevel]=Access
)
)
VAR AccessLevel=
IF (AccessCount>1&&Access<>0,Access-1,Access)
VAR Result=
IF (
AccessLevel<>3,
VALUE ( MIN ('Dim_Analysis'[LB_LEVEL]))-AccessLevel,
VALUE ( MIN ('Dim_Analysis'[LB_LEVEL]))-2
)
RETURN
IF (Result=1, SELECTEDMEASURE (), BLANK () )

结果如下:

补充
-
若部门连接类别,类别连接事实表,则不会存在此问题
-
上述问题的诱因,也存在笛卡尔积的原因,导致内部计值流发生了变化
特别鸣谢夕枫大佬



网友评论