对于非管理员用户,查询 `select count(distinct columnname)` 的结果为0
对于一个非管理员用户,拥有对一个视图的“Select”权限时,他们能够对行数进行计数并显示该SQL视图的所有内容:
select * from dbo.BackupInfoView;
select count(*) from dbo.BackupInfoView;
但在使用 Distinct 进行选择和计数时,他们得到的输出为零(数字为0):
select count(distinct clientname) from BackupInfoView;
管理员用户不会遇到这个问题。我也尝试将管理员权限赋予给该非管理员用户,他们能够从 'count distinct' 获得输出。
我已检查过RLS(行级安全),没有启用。
该非管理员用户对视图中的所有列都具有“Select”权限。
解决方案
修复与UNMASK权限相关。尽管该用户账户能够成功查询整个视图BackupInfoView,但有一个与视图连接的表的列启用了动态屏蔽。
我查看了该视图的源代码,找到了该列所在的表及列名,然后为该列授予该用户UNMASK权限:
EXEC sp_help 'dbo.BackupInfoView'
GRANT UNMASK to 'dbo.BackupDetail.column-name' to db-user
从EXEC行的输出中,我发现原始表是BackupDetail,而且 "column-name" 与我在 'BackupInfoView' 视图中查询的列是同一列。请相应地替换 "column-name" 和 "db-user"。
希望这能帮助遇到类似问题的其他人。
备选方案
正如你在自己的回答中所指出的,该列使用了 Data Masking,并且该用户没有 UNMASK 权限。
在将屏蔽列用于其他表达式的情况下,屏蔽不是在读取列的时刻应用,而是在输出前的最顶层表达式 SELECT 处应用。因此,预计 COUNT(DISTINCT clientname) 表达式会被屏蔽,整数的默认掩码为零。
但这种检测相当直白,也比较容易被规避。例如,你可以通过使用嵌套的 GROUP BY 来改写查询,以避免输出该列及其任何派生列。这也是不应将Data Masking作为安全策略的原因之一。
SELECT COUNT(*)
FROM (
SELECT DISTINCT clientname
FROM dbo.BackupInfoView;
GROUP BY clientname
) t;