为啥 COUNT(*) 需要对 SQL Server 上的所有表列具有 SELECT 权限?
Posted
技术标签:
【中文标题】为啥 COUNT(*) 需要对 SQL Server 上的所有表列具有 SELECT 权限?【英文标题】:Why does COUNT(*) require SELECT permission on all table columns on SQL Server?为什么 COUNT(*) 需要对 SQL Server 上的所有表列具有 SELECT 权限? 【发布时间】:2020-01-02 11:34:20 【问题描述】:我最近遇到COUNT(*)
要求用户对表的每一列都有选择权限的问题。
尽管spec of 'COUNT(*)' 明确表示
它不使用任何特定列的信息。
它只返回结果中的行数。
因此,如果您想将表中的行数计算为受限用户,则会出现权限异常。
这是一个例子:
CREATE TABLE [Product]
([name] nvarchar(100) null, [price] float)
CREATE USER Intern WITHOUT LOGIN;
DENY SELECT ON [Product] (price) TO Intern;
EXECUTE AS Intern;
-- Fails with "The SELECT permission was denied on the column 'price' of the object 'Product'"
SELECT COUNT(*) FROM [Product];
REVERT;
经过一些测试,我发现即使
SELECT COUNT(1) FROM [Product]
不起作用。
有人可以解释这种行为背后的原因是什么吗?
什么是允许Intern
用户仍然获得Product
的准确计数的解决方法。
更新: 我对实习生可以使用的解决方法最感兴趣。因此,即使创建视图是管理员的最佳实践,实习生也没有此选项。
【问题讨论】:
你试过select count(1) ...
吗?
select count(name)
工作吗?
最好的解决方案可能是创建一个明确排除 Intern
不应该看到的列的视图,并授予 SELECT
权限。这样,查询就可以正常工作,而不必引入迂回和不直观的变通办法,并且您也不需要每列单独的DENY
权限——您不必首先授予基表上的SELECT
权限。当您开始拒绝访问各个列时,COUNT(*)
可能不是唯一会造成不便的事情。
@JeroenMostert 你说得对,创建视图是最好的解决方案,我最感兴趣的是实习生如何解决这个问题,他大概无法创建视图。
@pascalsanchez 您将空名称转换为其他名称的解决方案。这些解决方案唯一不是最佳的部分是性能稍差。
【参考方案1】:
我不知道这种行为背后的原因,但有办法解决它:
SELECT COUNT(1)
FROM (
SELECT P.name
FROM dbo.Product AS P
) AS t;
当然,您需要对 Product.name 具有 SELECT 权限,但我从您的 cmets 收集到这应该不是问题。
附录,因为我同意这是意外行为。如果您执行以下操作,您还可以执行计数(如果您在 name
上拥有索引以及在 name
上拥有 SELECT 权限):
SELECT COUNT(1)
FROM dbo.Product AS P
WHERE P.name = P.name
OR P.name IS NULL
从想要一些他们不允许的东西的用户的角度来看,前面的工作很好(在这种情况下是实习生)。从 DBA 的角度来看,存在一种更好的方法来方便该用户。 (抄自上面 Jeroen Mostert 的评论:)
您可以创建一个明确排除实习生应该排除的列的视图 看不到,并授予 SELECT 权限。这样,查询工作 像往常一样,不必介绍迂回和不直观 解决方法,并且您不需要每列单独的 DENY 权限 或者——您不必授予对基表的 SELECT 权限 首先。
【讨论】:
我尝试了您的第二个解决方案,它确实有效(即使没有索引)。这真的很令人惊讶,似乎添加 WHERE 子句会以某种方式改变 count(*) 的含义?? 我试过SELECT COUNT(1) FROM dbo.Product WHERE P.name = P.name OR 1=1
,它确实有效并且是正确的。以上是关于为啥 COUNT(*) 需要对 SQL Server 上的所有表列具有 SELECT 权限?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 SQL SELECT 语句在 Java Spring boot 项目中不返回 COUNT() 结果?
为啥按 count(lab_results.testid) desc 排序在 C# 中不起作用 - 但在 SQL Server 中很好?
为啥 Linq-to-SQL 会添加不必要的 COUNT()?
为啥sql查询语句中的count(*)等聚合函数可以放在having后面,而不能放在where后面?