对于非管理员用户,查询 `select count(distinct columnname)` 的结果为0

编程语言 2026-07-08

对于一个非管理员用户,拥有对一个视图的“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;

db<>fiddle

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章